mcp-security-framework 1.1.0__py3-none-any.whl → 1.1.2__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.2.dist-info}/METADATA +4 -3
  34. mcp_security_framework-1.1.2.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.2.dist-info}/WHEEL +0 -0
  57. {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.2.dist-info}/entry_points.txt +0 -0
  58. {mcp_security_framework-1.1.0.dist-info → mcp_security_framework-1.1.2.dist-info}/top_level.txt +0 -0
@@ -4,10 +4,11 @@ Certificate CLI Tests
4
4
  This module contains tests for the certificate management CLI commands.
5
5
  """
6
6
 
7
- import pytest
8
- import tempfile
9
7
  import os
10
- from unittest.mock import Mock, patch, mock_open, MagicMock
8
+ import tempfile
9
+ from unittest.mock import MagicMock, Mock, mock_open, patch
10
+
11
+ import pytest
11
12
  from click.testing import CliRunner
12
13
 
13
14
  from mcp_security_framework.cli.cert_cli import cert_cli
@@ -17,34 +18,35 @@ from mcp_security_framework.schemas.models import CertificatePair, CertificateTy
17
18
 
18
19
  class TestCertCLI:
19
20
  """Test suite for certificate CLI commands."""
20
-
21
+
21
22
  def setup_method(self):
22
23
  """Set up test fixtures."""
23
24
  self.runner = CliRunner()
24
25
  self.temp_dir = tempfile.mkdtemp()
25
-
26
+
26
27
  # Create test certificate files
27
28
  self.test_cert_path = os.path.join(self.temp_dir, "test.crt")
28
29
  self.test_key_path = os.path.join(self.temp_dir, "test.key")
29
-
30
- with open(self.test_cert_path, 'w') as f:
30
+
31
+ with open(self.test_cert_path, "w") as f:
31
32
  f.write("-----BEGIN CERTIFICATE-----\nTEST CERT\n-----END CERTIFICATE-----")
32
-
33
- with open(self.test_key_path, 'w') as f:
33
+
34
+ with open(self.test_key_path, "w") as f:
34
35
  f.write("-----BEGIN PRIVATE KEY-----\nTEST KEY\n-----END PRIVATE KEY-----")
35
-
36
+
36
37
  def teardown_method(self):
37
38
  """Clean up test fixtures."""
38
39
  import shutil
40
+
39
41
  shutil.rmtree(self.temp_dir, ignore_errors=True)
40
-
41
- @patch('mcp_security_framework.cli.cert_cli.CertificateManager')
42
+
43
+ @patch("mcp_security_framework.cli.cert_cli.CertificateManager")
42
44
  def test_create_ca_success(self, mock_cert_manager_class):
43
45
  """Test successful CA certificate creation."""
44
46
  # Mock certificate manager
45
47
  mock_cert_manager = Mock()
46
48
  mock_cert_manager_class.return_value = mock_cert_manager
47
-
49
+
48
50
  # Mock certificate pair
49
51
  mock_cert_pair = Mock(spec=CertificatePair)
50
52
  mock_cert_pair.certificate_path = "/path/to/ca.crt"
@@ -52,101 +54,107 @@ class TestCertCLI:
52
54
  mock_cert_pair.serial_number = "123456789"
53
55
  mock_cert_pair.not_after = "2025-01-01"
54
56
  mock_cert_manager.create_root_ca.return_value = mock_cert_pair
55
-
57
+
56
58
  # Run command
57
- result = self.runner.invoke(cert_cli, [
58
- 'create-ca',
59
- '--common-name', 'Test CA',
60
- '--organization', 'Test Org',
61
- '--country', 'US'
62
- ])
63
-
59
+ result = self.runner.invoke(
60
+ cert_cli,
61
+ [
62
+ "create-ca",
63
+ "--common-name",
64
+ "Test CA",
65
+ "--organization",
66
+ "Test Org",
67
+ "--country",
68
+ "US",
69
+ ],
70
+ )
71
+
64
72
  # Assertions
65
73
  assert result.exit_code == 0
66
74
  assert "✅ CA certificate created successfully!" in result.output
67
75
  # Note: The output doesn't include the input parameters, only the result
68
-
69
- @patch('mcp_security_framework.cli.cert_cli.CertificateManager')
76
+
77
+ @patch("mcp_security_framework.cli.cert_cli.CertificateManager")
70
78
  def test_create_ca_failure(self, mock_cert_manager_class):
71
79
  """Test CA certificate creation failure."""
72
80
  # Mock certificate manager
73
81
  mock_cert_manager = Mock()
74
82
  mock_cert_manager_class.return_value = mock_cert_manager
75
83
  mock_cert_manager.create_root_ca.side_effect = Exception("Test error")
76
-
84
+
77
85
  # Run command
78
- result = self.runner.invoke(cert_cli, [
79
- 'create-ca',
80
- '--common-name', 'Test CA',
81
- '--organization', 'Test Org',
82
- '--country', 'US'
83
- ])
84
-
86
+ result = self.runner.invoke(
87
+ cert_cli,
88
+ [
89
+ "create-ca",
90
+ "--common-name",
91
+ "Test CA",
92
+ "--organization",
93
+ "Test Org",
94
+ "--country",
95
+ "US",
96
+ ],
97
+ )
98
+
85
99
  # Assertions
86
100
  assert result.exit_code != 0
87
101
  assert "❌ Failed to create CA certificate" in result.output
88
-
102
+
89
103
  def test_create_server_success(self):
90
104
  """Test successful server certificate creation."""
91
105
  # Create a simple test that doesn't require complex mocking
92
- result = self.runner.invoke(cert_cli, ['--help'])
93
-
106
+ result = self.runner.invoke(cert_cli, ["--help"])
107
+
94
108
  # Assertions - just check that CLI is working
95
109
  assert result.exit_code == 0
96
110
  assert "Certificate Management CLI" in result.output
97
-
111
+
98
112
  def test_create_client_success(self):
99
113
  """Test successful client certificate creation."""
100
114
  # Create a simple test that doesn't require complex mocking
101
- result = self.runner.invoke(cert_cli, ['create-client', '--help'])
102
-
115
+ result = self.runner.invoke(cert_cli, ["create-client", "--help"])
116
+
103
117
  # Assertions - just check that CLI command is available
104
118
  assert result.exit_code == 0
105
119
  assert "Create a client certificate" in result.output
106
-
107
- @patch('mcp_security_framework.cli.cert_cli.CertificateManager')
120
+
121
+ @patch("mcp_security_framework.cli.cert_cli.CertificateManager")
108
122
  def test_validate_success(self, mock_cert_manager_class):
109
123
  """Test successful certificate validation."""
110
124
  # Mock certificate manager
111
125
  mock_cert_manager = Mock()
112
126
  mock_cert_manager_class.return_value = mock_cert_manager
113
127
  mock_cert_manager.validate_certificate_chain.return_value = True
114
-
128
+
115
129
  # Run command
116
- result = self.runner.invoke(cert_cli, [
117
- 'validate',
118
- self.test_cert_path
119
- ])
120
-
130
+ result = self.runner.invoke(cert_cli, ["validate", self.test_cert_path])
131
+
121
132
  # Assertions
122
133
  assert result.exit_code == 0
123
134
  assert "✅ Certificate is valid!" in result.output
124
-
125
- @patch('mcp_security_framework.cli.cert_cli.CertificateManager')
135
+
136
+ @patch("mcp_security_framework.cli.cert_cli.CertificateManager")
126
137
  def test_validate_failure(self, mock_cert_manager_class):
127
138
  """Test certificate validation failure."""
128
139
  # Mock certificate manager
129
140
  mock_cert_manager = Mock()
130
141
  mock_cert_manager_class.return_value = mock_cert_manager
131
142
  mock_cert_manager.validate_certificate_chain.return_value = False
132
-
143
+
133
144
  # Run command
134
- result = self.runner.invoke(cert_cli, [
135
- 'validate',
136
- self.test_cert_path
137
- ])
138
-
145
+ result = self.runner.invoke(cert_cli, ["validate", self.test_cert_path])
146
+
139
147
  # Assertions
140
148
  assert result.exit_code != 0
141
149
  assert "❌ Certificate validation failed!" in result.output
142
-
143
- @patch('mcp_security_framework.cli.cert_cli.CertificateManager')
150
+
151
+ @patch("mcp_security_framework.cli.cert_cli.CertificateManager")
144
152
  def test_info_success(self, mock_cert_manager_class):
145
153
  """Test successful certificate info display."""
146
154
  # Mock certificate manager
147
155
  mock_cert_manager = Mock()
148
156
  mock_cert_manager_class.return_value = mock_cert_manager
149
-
157
+
150
158
  # Mock certificate info
151
159
  mock_cert_info = Mock()
152
160
  mock_cert_info.subject = {"CN": "test.example.com"}
@@ -158,96 +166,91 @@ class TestCertCLI:
158
166
  mock_cert_info.certificate_type = CertificateType.SERVER
159
167
  mock_cert_info.subject_alt_names = ["test.example.com"]
160
168
  mock_cert_manager.get_certificate_info.return_value = mock_cert_info
161
-
169
+
162
170
  # Run command
163
- result = self.runner.invoke(cert_cli, [
164
- 'info',
165
- self.test_cert_path
166
- ])
167
-
171
+ result = self.runner.invoke(cert_cli, ["info", self.test_cert_path])
172
+
168
173
  # Assertions
169
174
  assert result.exit_code == 0
170
175
  assert "Certificate Information:" in result.output
171
176
  assert "test.example.com" in result.output
172
-
173
- @patch('mcp_security_framework.cli.cert_cli.CertificateManager')
177
+
178
+ @patch("mcp_security_framework.cli.cert_cli.CertificateManager")
174
179
  def test_revoke_success(self, mock_cert_manager_class):
175
180
  """Test successful certificate revocation."""
176
181
  # Mock certificate manager
177
182
  mock_cert_manager = Mock()
178
183
  mock_cert_manager_class.return_value = mock_cert_manager
179
184
  mock_cert_manager.revoke_certificate.return_value = True
180
-
185
+
181
186
  # Run command
182
- result = self.runner.invoke(cert_cli, [
183
- 'revoke',
184
- '123456789',
185
- '--reason', 'compromised'
186
- ])
187
-
187
+ result = self.runner.invoke(
188
+ cert_cli, ["revoke", "123456789", "--reason", "compromised"]
189
+ )
190
+
188
191
  # Assertions
189
192
  assert result.exit_code == 0
190
193
  assert "✅ Certificate revoked successfully!" in result.output
191
-
192
- @patch('mcp_security_framework.cli.cert_cli.CertificateManager')
194
+
195
+ @patch("mcp_security_framework.cli.cert_cli.CertificateManager")
193
196
  def test_revoke_failure(self, mock_cert_manager_class):
194
197
  """Test certificate revocation failure."""
195
198
  # Mock certificate manager
196
199
  mock_cert_manager = Mock()
197
200
  mock_cert_manager_class.return_value = mock_cert_manager
198
201
  mock_cert_manager.revoke_certificate.return_value = False
199
-
202
+
200
203
  # Run command
201
- result = self.runner.invoke(cert_cli, [
202
- 'revoke',
203
- '123456789',
204
- '--reason', 'compromised'
205
- ])
206
-
204
+ result = self.runner.invoke(
205
+ cert_cli, ["revoke", "123456789", "--reason", "compromised"]
206
+ )
207
+
207
208
  # Assertions
208
209
  assert result.exit_code != 0
209
210
  assert "❌ Failed to revoke certificate!" in result.output
210
-
211
+
211
212
  def test_help(self):
212
213
  """Test CLI help output."""
213
- result = self.runner.invoke(cert_cli, ['--help'])
214
+ result = self.runner.invoke(cert_cli, ["--help"])
214
215
  assert result.exit_code == 0
215
216
  assert "Certificate Management CLI" in result.output
216
-
217
- @patch('mcp_security_framework.cli.cert_cli.CertificateManager')
217
+
218
+ @patch("mcp_security_framework.cli.cert_cli.CertificateManager")
218
219
  def test_create_ca_help(self, mock_cert_manager_class):
219
220
  """Test create-ca help output."""
220
221
  # Mock certificate manager
221
222
  mock_cert_manager = Mock()
222
223
  mock_cert_manager_class.return_value = mock_cert_manager
223
-
224
- result = self.runner.invoke(cert_cli, ['create-ca', '--help'])
224
+
225
+ result = self.runner.invoke(cert_cli, ["create-ca", "--help"])
225
226
  assert result.exit_code == 0
226
227
  assert "Create a root CA certificate" in result.output
227
-
228
- @patch('mcp_security_framework.cli.cert_cli.CertificateManager')
228
+
229
+ @patch("mcp_security_framework.cli.cert_cli.CertificateManager")
229
230
  def test_missing_required_options(self, mock_cert_manager_class):
230
231
  """Test missing required options."""
231
232
  # Mock certificate manager
232
233
  mock_cert_manager = Mock()
233
234
  mock_cert_manager_class.return_value = mock_cert_manager
234
-
235
- result = self.runner.invoke(cert_cli, ['create-ca'])
235
+
236
+ result = self.runner.invoke(cert_cli, ["create-ca"])
236
237
  assert result.exit_code != 0
237
238
  assert "Missing option" in result.output
238
239
 
239
- @patch('mcp_security_framework.cli.cert_cli.CertificateManager')
240
- @patch('mcp_security_framework.cli.cert_cli.CertificateConfig')
241
- def test_create_intermediate_ca_success(self, mock_config_class, mock_cert_manager_class):
240
+ @patch("mcp_security_framework.cli.cert_cli.CertificateManager")
241
+ @patch("mcp_security_framework.cli.cert_cli.CertificateConfig")
242
+ def test_create_intermediate_ca_success(
243
+ self, mock_config_class, mock_cert_manager_class
244
+ ):
242
245
  """Test successful intermediate CA certificate creation."""
243
246
  # Mock configuration
244
247
  mock_config = Mock()
245
248
  mock_config_class.return_value = mock_config
246
-
249
+
247
250
  # Mock certificate manager
248
251
  mock_cert_manager = Mock()
249
252
  mock_cert_manager_class.return_value = mock_cert_manager
250
-
253
+
251
254
  # Mock certificate pair
252
255
  mock_cert_pair = Mock(spec=CertificatePair)
253
256
  mock_cert_pair.certificate_path = "/path/to/intermediate_ca.crt"
@@ -255,107 +258,142 @@ class TestCertCLI:
255
258
  mock_cert_pair.serial_number = "123456789"
256
259
  mock_cert_pair.not_after = "2025-01-01"
257
260
  mock_cert_manager.create_intermediate_ca.return_value = mock_cert_pair
258
-
261
+
259
262
  # Create temporary config file
260
263
  config_file = os.path.join(self.temp_dir, "test_config.json")
261
- with open(config_file, 'w') as f:
264
+ with open(config_file, "w") as f:
262
265
  f.write('{"cert_storage_path": "./certs", "key_storage_path": "./keys"}')
263
-
266
+
264
267
  # Run command
265
- result = self.runner.invoke(cert_cli, [
266
- '--config', config_file,
267
- 'create-intermediate-ca',
268
- '--common-name', 'Test Intermediate CA',
269
- '--organization', 'Test Org',
270
- '--country', 'US',
271
- '--parent-ca-cert', '/path/to/parent_ca.crt',
272
- '--parent-ca-key', '/path/to/parent_ca.key'
273
- ])
274
-
268
+ result = self.runner.invoke(
269
+ cert_cli,
270
+ [
271
+ "--config",
272
+ config_file,
273
+ "create-intermediate-ca",
274
+ "--common-name",
275
+ "Test Intermediate CA",
276
+ "--organization",
277
+ "Test Org",
278
+ "--country",
279
+ "US",
280
+ "--parent-ca-cert",
281
+ "/path/to/parent_ca.crt",
282
+ "--parent-ca-key",
283
+ "/path/to/parent_ca.key",
284
+ ],
285
+ )
286
+
275
287
  # Assertions
276
288
  assert result.exit_code == 0
277
289
  assert "✅ Intermediate CA certificate created successfully!" in result.output
278
290
 
279
- @patch('mcp_security_framework.cli.cert_cli.CertificateManager')
291
+ @patch("mcp_security_framework.cli.cert_cli.CertificateManager")
280
292
  def test_create_intermediate_ca_failure(self, mock_cert_manager_class):
281
293
  """Test intermediate CA certificate creation failure."""
282
294
  # Mock certificate manager
283
295
  mock_cert_manager = Mock()
284
296
  mock_cert_manager_class.return_value = mock_cert_manager
285
297
  mock_cert_manager.create_intermediate_ca.side_effect = Exception("Test error")
286
-
298
+
287
299
  # Run command
288
- result = self.runner.invoke(cert_cli, [
289
- 'create-intermediate-ca',
290
- '--common-name', 'Test Intermediate CA',
291
- '--organization', 'Test Org',
292
- '--country', 'US',
293
- '--parent-ca-cert', '/path/to/parent_ca.crt',
294
- '--parent-ca-key', '/path/to/parent_ca.key'
295
- ])
296
-
300
+ result = self.runner.invoke(
301
+ cert_cli,
302
+ [
303
+ "create-intermediate-ca",
304
+ "--common-name",
305
+ "Test Intermediate CA",
306
+ "--organization",
307
+ "Test Org",
308
+ "--country",
309
+ "US",
310
+ "--parent-ca-cert",
311
+ "/path/to/parent_ca.crt",
312
+ "--parent-ca-key",
313
+ "/path/to/parent_ca.key",
314
+ ],
315
+ )
316
+
297
317
  # Assertions
298
318
  assert result.exit_code != 0
299
319
  assert "❌ Failed to create intermediate CA certificate" in result.output
300
320
 
301
- @patch('mcp_security_framework.cli.cert_cli.CertificateManager')
321
+ @patch("mcp_security_framework.cli.cert_cli.CertificateManager")
302
322
  def test_create_crl_success(self, mock_cert_manager_class):
303
323
  """Test successful CRL creation."""
304
324
  # Mock certificate manager
305
325
  mock_cert_manager = Mock()
306
326
  mock_cert_manager_class.return_value = mock_cert_manager
307
327
  mock_cert_manager.create_crl.return_value = "/path/to/crl.pem"
308
-
328
+
309
329
  # Run command
310
- result = self.runner.invoke(cert_cli, [
311
- 'create-crl',
312
- '--ca-cert', '/path/to/ca.crt',
313
- '--ca-key', '/path/to/ca.key',
314
- '--validity-days', '30'
315
- ])
316
-
330
+ result = self.runner.invoke(
331
+ cert_cli,
332
+ [
333
+ "create-crl",
334
+ "--ca-cert",
335
+ "/path/to/ca.crt",
336
+ "--ca-key",
337
+ "/path/to/ca.key",
338
+ "--validity-days",
339
+ "30",
340
+ ],
341
+ )
342
+
317
343
  # Assertions
318
344
  assert result.exit_code == 0
319
345
  assert "✅ CRL created successfully!" in result.output
320
346
  assert "/path/to/crl.pem" in result.output
321
347
 
322
- @patch('mcp_security_framework.cli.cert_cli.CertificateManager')
348
+ @patch("mcp_security_framework.cli.cert_cli.CertificateManager")
323
349
  def test_create_crl_with_output(self, mock_cert_manager_class):
324
350
  """Test CRL creation with custom output path."""
325
351
  # Mock certificate manager
326
352
  mock_cert_manager = Mock()
327
353
  mock_cert_manager_class.return_value = mock_cert_manager
328
354
  mock_cert_manager.create_crl.return_value = "/custom/path/crl.pem"
329
-
355
+
330
356
  # Run command
331
- result = self.runner.invoke(cert_cli, [
332
- 'create-crl',
333
- '--ca-cert', '/path/to/ca.crt',
334
- '--ca-key', '/path/to/ca.key',
335
- '--output', '/custom/path/crl.pem',
336
- '--validity-days', '60'
337
- ])
338
-
357
+ result = self.runner.invoke(
358
+ cert_cli,
359
+ [
360
+ "create-crl",
361
+ "--ca-cert",
362
+ "/path/to/ca.crt",
363
+ "--ca-key",
364
+ "/path/to/ca.key",
365
+ "--output",
366
+ "/custom/path/crl.pem",
367
+ "--validity-days",
368
+ "60",
369
+ ],
370
+ )
371
+
339
372
  # Assertions
340
373
  assert result.exit_code == 0
341
374
  assert "✅ CRL created successfully!" in result.output
342
375
  assert "/custom/path/crl.pem" in result.output
343
376
 
344
- @patch('mcp_security_framework.cli.cert_cli.CertificateManager')
377
+ @patch("mcp_security_framework.cli.cert_cli.CertificateManager")
345
378
  def test_create_crl_failure(self, mock_cert_manager_class):
346
379
  """Test CRL creation failure."""
347
380
  # Mock certificate manager
348
381
  mock_cert_manager = Mock()
349
382
  mock_cert_manager_class.return_value = mock_cert_manager
350
383
  mock_cert_manager.create_crl.side_effect = Exception("Test error")
351
-
384
+
352
385
  # Run command
353
- result = self.runner.invoke(cert_cli, [
354
- 'create-crl',
355
- '--ca-cert', '/path/to/ca.crt',
356
- '--ca-key', '/path/to/ca.key'
357
- ])
358
-
386
+ result = self.runner.invoke(
387
+ cert_cli,
388
+ [
389
+ "create-crl",
390
+ "--ca-cert",
391
+ "/path/to/ca.crt",
392
+ "--ca-key",
393
+ "/path/to/ca.key",
394
+ ],
395
+ )
396
+
359
397
  # Assertions
360
398
  assert result.exit_code != 0
361
399
  assert "❌ Failed to create CRL" in result.output