mcp-proxy-adapter 6.3.4__py3-none-any.whl → 6.3.6__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 (131) hide show
  1. mcp_proxy_adapter/__init__.py +9 -5
  2. mcp_proxy_adapter/__main__.py +1 -1
  3. mcp_proxy_adapter/api/app.py +227 -176
  4. mcp_proxy_adapter/api/handlers.py +68 -60
  5. mcp_proxy_adapter/api/middleware/__init__.py +7 -5
  6. mcp_proxy_adapter/api/middleware/base.py +19 -16
  7. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
  8. mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
  9. mcp_proxy_adapter/api/middleware/factory.py +50 -52
  10. mcp_proxy_adapter/api/middleware/logging.py +46 -30
  11. mcp_proxy_adapter/api/middleware/performance.py +19 -16
  12. mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
  13. mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
  14. mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
  15. mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
  16. mcp_proxy_adapter/api/schemas.py +69 -43
  17. mcp_proxy_adapter/api/tool_integration.py +83 -63
  18. mcp_proxy_adapter/api/tools.py +60 -50
  19. mcp_proxy_adapter/commands/__init__.py +15 -6
  20. mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
  21. mcp_proxy_adapter/commands/base.py +108 -112
  22. mcp_proxy_adapter/commands/builtin_commands.py +28 -18
  23. mcp_proxy_adapter/commands/catalog_manager.py +394 -265
  24. mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
  25. mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
  26. mcp_proxy_adapter/commands/command_registry.py +275 -226
  27. mcp_proxy_adapter/commands/config_command.py +48 -33
  28. mcp_proxy_adapter/commands/dependency_container.py +22 -23
  29. mcp_proxy_adapter/commands/dependency_manager.py +65 -56
  30. mcp_proxy_adapter/commands/echo_command.py +15 -15
  31. mcp_proxy_adapter/commands/health_command.py +31 -29
  32. mcp_proxy_adapter/commands/help_command.py +97 -61
  33. mcp_proxy_adapter/commands/hooks.py +65 -49
  34. mcp_proxy_adapter/commands/key_management_command.py +148 -147
  35. mcp_proxy_adapter/commands/load_command.py +58 -40
  36. mcp_proxy_adapter/commands/plugins_command.py +80 -54
  37. mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
  38. mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
  39. mcp_proxy_adapter/commands/reload_command.py +43 -37
  40. mcp_proxy_adapter/commands/result.py +26 -33
  41. mcp_proxy_adapter/commands/role_test_command.py +26 -26
  42. mcp_proxy_adapter/commands/roles_management_command.py +176 -173
  43. mcp_proxy_adapter/commands/security_command.py +134 -122
  44. mcp_proxy_adapter/commands/settings_command.py +47 -56
  45. mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
  46. mcp_proxy_adapter/commands/token_management_command.py +129 -158
  47. mcp_proxy_adapter/commands/transport_management_command.py +41 -36
  48. mcp_proxy_adapter/commands/unload_command.py +42 -37
  49. mcp_proxy_adapter/config.py +36 -35
  50. mcp_proxy_adapter/core/__init__.py +19 -21
  51. mcp_proxy_adapter/core/app_factory.py +30 -9
  52. mcp_proxy_adapter/core/app_runner.py +81 -64
  53. mcp_proxy_adapter/core/auth_validator.py +176 -182
  54. mcp_proxy_adapter/core/certificate_utils.py +469 -426
  55. mcp_proxy_adapter/core/client.py +155 -126
  56. mcp_proxy_adapter/core/client_manager.py +60 -54
  57. mcp_proxy_adapter/core/client_security.py +120 -91
  58. mcp_proxy_adapter/core/config_converter.py +176 -143
  59. mcp_proxy_adapter/core/config_validator.py +12 -4
  60. mcp_proxy_adapter/core/crl_utils.py +21 -7
  61. mcp_proxy_adapter/core/errors.py +64 -20
  62. mcp_proxy_adapter/core/logging.py +34 -29
  63. mcp_proxy_adapter/core/mtls_asgi.py +29 -25
  64. mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
  65. mcp_proxy_adapter/core/protocol_manager.py +154 -104
  66. mcp_proxy_adapter/core/proxy_client.py +202 -144
  67. mcp_proxy_adapter/core/proxy_registration.py +7 -3
  68. mcp_proxy_adapter/core/role_utils.py +139 -125
  69. mcp_proxy_adapter/core/security_adapter.py +88 -77
  70. mcp_proxy_adapter/core/security_factory.py +50 -44
  71. mcp_proxy_adapter/core/security_integration.py +72 -24
  72. mcp_proxy_adapter/core/server_adapter.py +68 -64
  73. mcp_proxy_adapter/core/server_engine.py +71 -53
  74. mcp_proxy_adapter/core/settings.py +68 -58
  75. mcp_proxy_adapter/core/ssl_utils.py +69 -56
  76. mcp_proxy_adapter/core/transport_manager.py +72 -60
  77. mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
  78. mcp_proxy_adapter/core/utils.py +4 -2
  79. mcp_proxy_adapter/custom_openapi.py +107 -99
  80. mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
  81. mcp_proxy_adapter/examples/commands/__init__.py +1 -1
  82. mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
  83. mcp_proxy_adapter/examples/debug_request_state.py +38 -19
  84. mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
  85. mcp_proxy_adapter/examples/demo_client.py +48 -36
  86. mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
  87. mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
  88. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
  89. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  90. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
  91. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  92. mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
  93. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
  94. mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
  95. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
  96. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  97. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
  98. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  99. mcp_proxy_adapter/examples/full_application/main.py +27 -2
  100. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
  101. mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
  102. mcp_proxy_adapter/examples/generate_certificates.py +31 -16
  103. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
  104. mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
  105. mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
  106. mcp_proxy_adapter/examples/run_example.py +23 -5
  107. mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
  108. mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
  109. mcp_proxy_adapter/examples/run_security_tests.py +103 -41
  110. mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
  111. mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
  112. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
  113. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
  114. mcp_proxy_adapter/examples/security_test_client.py +196 -127
  115. mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
  116. mcp_proxy_adapter/examples/test_config.py +19 -4
  117. mcp_proxy_adapter/examples/test_config_generator.py +23 -7
  118. mcp_proxy_adapter/examples/test_examples.py +84 -56
  119. mcp_proxy_adapter/examples/universal_client.py +119 -62
  120. mcp_proxy_adapter/openapi.py +108 -115
  121. mcp_proxy_adapter/utils/config_generator.py +429 -274
  122. mcp_proxy_adapter/version.py +1 -2
  123. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/METADATA +1 -1
  124. mcp_proxy_adapter-6.3.6.dist-info/RECORD +144 -0
  125. mcp_proxy_adapter-6.3.6.dist-info/top_level.txt +2 -0
  126. mcp_proxy_adapter_issue_package/demonstrate_issue.py +178 -0
  127. mcp_proxy_adapter-6.3.4.dist-info/RECORD +0 -143
  128. mcp_proxy_adapter-6.3.4.dist-info/top_level.txt +0 -1
  129. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/WHEEL +0 -0
  130. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/entry_points.txt +0 -0
  131. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/licenses/LICENSE +0 -0
@@ -345,16 +345,20 @@ class ProxyRegistrationManager:
345
345
  error_info = result.get("error", {})
346
346
  error_msg = error_info.get("message", "Unknown error")
347
347
  error_code = error_info.get("code", "UNKNOWN_ERROR")
348
-
348
+
349
349
  # Handle duplicate server URL as successful registration
350
350
  if error_code == "DUPLICATE_SERVER_URL":
351
- logger.info(f"✅ Server already registered: {error_msg}")
351
+ logger.info(
352
+ f"✅ Server already registered: {error_msg}"
353
+ )
352
354
  # Extract server_key from details if available
353
355
  details = error_info.get("details", {})
354
356
  existing_server_key = details.get("existing_server_key")
355
357
  if existing_server_key:
356
358
  result["server_key"] = existing_server_key
357
- logger.info(f"✅ Retrieved existing server key: {existing_server_key}")
359
+ logger.info(
360
+ f"✅ Retrieved existing server key: {existing_server_key}"
361
+ )
358
362
  # Return success=True for duplicate registration
359
363
  return True, result
360
364
  else:
@@ -16,50 +16,54 @@ from cryptography import x509
16
16
  class RoleUtils:
17
17
  """
18
18
  Utilities for working with roles from certificates.
19
-
19
+
20
20
  Provides methods for extracting, comparing, validating, and normalizing roles.
21
21
  """
22
-
22
+
23
23
  # Custom OID for roles in certificates
24
24
  ROLE_EXTENSION_OID = "1.3.6.1.4.1.99999.1"
25
-
25
+
26
26
  @staticmethod
27
27
  def extract_roles_from_certificate(cert_path: str) -> List[str]:
28
28
  """
29
29
  Extract roles from certificate file.
30
-
30
+
31
31
  Args:
32
32
  cert_path: Path to certificate file
33
-
33
+
34
34
  Returns:
35
35
  List of roles extracted from certificate
36
36
  """
37
37
  try:
38
- with open(cert_path, 'rb') as f:
38
+ with open(cert_path, "rb") as f:
39
39
  cert_data = f.read()
40
-
40
+
41
41
  cert = x509.load_pem_x509_certificate(cert_data)
42
-
42
+
43
43
  # Extract roles from custom extension
44
44
  for extension in cert.extensions:
45
45
  if extension.oid.dotted_string == RoleUtils.ROLE_EXTENSION_OID:
46
- roles_data = extension.value.value.decode('utf-8')
47
- return [role.strip() for role in roles_data.split(',') if role.strip()]
48
-
46
+ roles_data = extension.value.value.decode("utf-8")
47
+ return [
48
+ role.strip() for role in roles_data.split(",") if role.strip()
49
+ ]
50
+
49
51
  return []
50
-
52
+
51
53
  except Exception as e:
52
- logging.getLogger(__name__).error(f"Failed to extract roles from certificate {cert_path}: {e}")
54
+ logging.getLogger(__name__).error(
55
+ f"Failed to extract roles from certificate {cert_path}: {e}"
56
+ )
53
57
  return []
54
-
58
+
55
59
  @staticmethod
56
60
  def extract_roles_from_certificate_object(cert: x509.Certificate) -> List[str]:
57
61
  """
58
62
  Extract roles from certificate object.
59
-
63
+
60
64
  Args:
61
65
  cert: Certificate object
62
-
66
+
63
67
  Returns:
64
68
  List of roles extracted from certificate
65
69
  """
@@ -67,360 +71,370 @@ class RoleUtils:
67
71
  # Extract roles from custom extension
68
72
  for extension in cert.extensions:
69
73
  if extension.oid.dotted_string == RoleUtils.ROLE_EXTENSION_OID:
70
- roles_data = extension.value.value.decode('utf-8')
71
- return [role.strip() for role in roles_data.split(',') if role.strip()]
72
-
74
+ roles_data = extension.value.value.decode("utf-8")
75
+ return [
76
+ role.strip() for role in roles_data.split(",") if role.strip()
77
+ ]
78
+
73
79
  return []
74
-
80
+
75
81
  except Exception as e:
76
- logging.getLogger(__name__).error(f"Failed to extract roles from certificate object: {e}")
82
+ logging.getLogger(__name__).error(
83
+ f"Failed to extract roles from certificate object: {e}"
84
+ )
77
85
  return []
78
-
86
+
79
87
  @staticmethod
80
88
  def compare_roles(role1: str, role2: str) -> bool:
81
89
  """
82
90
  Compare two roles (case-insensitive).
83
-
91
+
84
92
  Args:
85
93
  role1: First role to compare
86
94
  role2: Second role to compare
87
-
95
+
88
96
  Returns:
89
97
  True if roles are equal (case-insensitive), False otherwise
90
98
  """
91
99
  if not role1 or not role2:
92
100
  return False
93
-
101
+
94
102
  return role1.lower().strip() == role2.lower().strip()
95
-
103
+
96
104
  @staticmethod
97
105
  def compare_role_lists(roles1: List[str], roles2: List[str]) -> bool:
98
106
  """
99
107
  Compare two lists of roles (case-insensitive).
100
-
108
+
101
109
  Args:
102
110
  roles1: First list of roles
103
111
  roles2: Second list of roles
104
-
112
+
105
113
  Returns:
106
114
  True if role lists are equal (case-insensitive), False otherwise
107
115
  """
108
116
  if not roles1 and not roles2:
109
117
  return True
110
-
118
+
111
119
  if not roles1 or not roles2:
112
120
  return False
113
-
121
+
114
122
  # Normalize and sort both lists
115
- normalized_roles1 = sorted([role.lower().strip() for role in roles1 if role.strip()])
116
- normalized_roles2 = sorted([role.lower().strip() for role in roles2 if role.strip()])
117
-
123
+ normalized_roles1 = sorted(
124
+ [role.lower().strip() for role in roles1 if role.strip()]
125
+ )
126
+ normalized_roles2 = sorted(
127
+ [role.lower().strip() for role in roles2 if role.strip()]
128
+ )
129
+
118
130
  return normalized_roles1 == normalized_roles2
119
-
131
+
120
132
  @staticmethod
121
133
  def validate_roles(roles: List[str]) -> bool:
122
134
  """
123
135
  Validate list of roles.
124
-
136
+
125
137
  Args:
126
138
  roles: List of roles to validate
127
-
139
+
128
140
  Returns:
129
141
  True if roles are valid, False otherwise
130
142
  """
131
143
  if not isinstance(roles, list):
132
144
  return False
133
-
145
+
134
146
  for role in roles:
135
147
  if not RoleUtils.validate_single_role(role):
136
148
  return False
137
-
149
+
138
150
  return True
139
-
151
+
140
152
  @staticmethod
141
153
  def validate_single_role(role: str) -> bool:
142
154
  """
143
155
  Validate a single role.
144
-
156
+
145
157
  Args:
146
158
  role: Role string to validate
147
-
159
+
148
160
  Returns:
149
161
  True if role is valid, False otherwise
150
162
  """
151
163
  if not isinstance(role, str):
152
164
  return False
153
-
165
+
154
166
  # Check if role is not empty after trimming
155
167
  if not role.strip():
156
168
  return False
157
-
169
+
158
170
  # Check for valid characters (alphanumeric, hyphens, underscores)
159
- valid_chars = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_')
171
+ valid_chars = set(
172
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
173
+ )
160
174
  role_chars = set(role.lower())
161
-
175
+
162
176
  if not role_chars.issubset(valid_chars):
163
177
  return False
164
-
178
+
165
179
  # Check length (1-50 characters)
166
180
  if len(role) < 1 or len(role) > 50:
167
181
  return False
168
-
182
+
169
183
  return True
170
-
184
+
171
185
  @staticmethod
172
186
  def normalize_role(role: str) -> str:
173
187
  """
174
188
  Normalize role string.
175
-
189
+
176
190
  Args:
177
191
  role: Role string to normalize
178
-
192
+
179
193
  Returns:
180
194
  Normalized role string
181
195
  """
182
196
  if not role:
183
197
  return ""
184
-
198
+
185
199
  # Convert to lowercase and trim whitespace
186
200
  normalized = role.lower().strip()
187
-
201
+
188
202
  # Replace multiple spaces with single space
189
- normalized = ' '.join(normalized.split())
190
-
203
+ normalized = " ".join(normalized.split())
204
+
191
205
  # Replace spaces with hyphens
192
- normalized = normalized.replace(' ', '-')
193
-
206
+ normalized = normalized.replace(" ", "-")
207
+
194
208
  return normalized
195
-
209
+
196
210
  @staticmethod
197
211
  def normalize_roles(roles: List[str]) -> List[str]:
198
212
  """
199
213
  Normalize list of roles.
200
-
214
+
201
215
  Args:
202
216
  roles: List of roles to normalize
203
-
217
+
204
218
  Returns:
205
219
  List of normalized roles
206
220
  """
207
221
  if not roles:
208
222
  return []
209
-
223
+
210
224
  normalized = []
211
225
  for role in roles:
212
226
  normalized_role = RoleUtils.normalize_role(role)
213
227
  if normalized_role and normalized_role not in normalized:
214
228
  normalized.append(normalized_role)
215
-
229
+
216
230
  return normalized
217
-
231
+
218
232
  @staticmethod
219
233
  def has_role(user_roles: List[str], required_role: str) -> bool:
220
234
  """
221
235
  Check if user has required role.
222
-
236
+
223
237
  Args:
224
238
  user_roles: List of user roles
225
239
  required_role: Required role to check
226
-
240
+
227
241
  Returns:
228
242
  True if user has required role, False otherwise
229
243
  """
230
244
  if not user_roles or not required_role:
231
245
  return False
232
-
246
+
233
247
  normalized_required = RoleUtils.normalize_role(required_role)
234
248
  normalized_user_roles = RoleUtils.normalize_roles(user_roles)
235
-
249
+
236
250
  return normalized_required in normalized_user_roles
237
-
251
+
238
252
  @staticmethod
239
253
  def has_any_role(user_roles: List[str], required_roles: List[str]) -> bool:
240
254
  """
241
255
  Check if user has any of the required roles.
242
-
256
+
243
257
  Args:
244
258
  user_roles: List of user roles
245
259
  required_roles: List of required roles to check
246
-
260
+
247
261
  Returns:
248
262
  True if user has any required role, False otherwise
249
263
  """
250
264
  if not user_roles or not required_roles:
251
265
  return False
252
-
266
+
253
267
  normalized_user_roles = RoleUtils.normalize_roles(user_roles)
254
268
  normalized_required_roles = RoleUtils.normalize_roles(required_roles)
255
-
269
+
256
270
  return any(role in normalized_user_roles for role in normalized_required_roles)
257
-
271
+
258
272
  @staticmethod
259
273
  def has_all_roles(user_roles: List[str], required_roles: List[str]) -> bool:
260
274
  """
261
275
  Check if user has all required roles.
262
-
276
+
263
277
  Args:
264
278
  user_roles: List of user roles
265
279
  required_roles: List of required roles to check
266
-
280
+
267
281
  Returns:
268
282
  True if user has all required roles, False otherwise
269
283
  """
270
284
  if not user_roles or not required_roles:
271
285
  return False
272
-
286
+
273
287
  normalized_user_roles = RoleUtils.normalize_roles(user_roles)
274
288
  normalized_required_roles = RoleUtils.normalize_roles(required_roles)
275
-
289
+
276
290
  return all(role in normalized_user_roles for role in normalized_required_roles)
277
-
291
+
278
292
  @staticmethod
279
293
  def get_common_roles(roles1: List[str], roles2: List[str]) -> List[str]:
280
294
  """
281
295
  Get common roles between two role lists.
282
-
296
+
283
297
  Args:
284
298
  roles1: First list of roles
285
299
  roles2: Second list of roles
286
-
300
+
287
301
  Returns:
288
302
  List of common roles
289
303
  """
290
304
  if not roles1 or not roles2:
291
305
  return []
292
-
306
+
293
307
  normalized_roles1 = set(RoleUtils.normalize_roles(roles1))
294
308
  normalized_roles2 = set(RoleUtils.normalize_roles(roles2))
295
-
309
+
296
310
  return list(normalized_roles1.intersection(normalized_roles2))
297
-
311
+
298
312
  @staticmethod
299
313
  def merge_roles(roles1: List[str], roles2: List[str]) -> List[str]:
300
314
  """
301
315
  Merge two role lists (remove duplicates).
302
-
316
+
303
317
  Args:
304
318
  roles1: First list of roles
305
319
  roles2: Second list of roles
306
-
320
+
307
321
  Returns:
308
322
  Merged list of roles without duplicates
309
323
  """
310
324
  all_roles = (roles1 or []) + (roles2 or [])
311
325
  return RoleUtils.normalize_roles(all_roles)
312
-
326
+
313
327
  @staticmethod
314
328
  def remove_roles(roles: List[str], roles_to_remove: List[str]) -> List[str]:
315
329
  """
316
330
  Remove specified roles from role list.
317
-
331
+
318
332
  Args:
319
333
  roles: List of roles
320
334
  roles_to_remove: List of roles to remove
321
-
335
+
322
336
  Returns:
323
337
  List of roles with specified roles removed
324
338
  """
325
339
  if not roles:
326
340
  return []
327
-
341
+
328
342
  if not roles_to_remove:
329
343
  return roles.copy()
330
-
344
+
331
345
  normalized_roles = RoleUtils.normalize_roles(roles)
332
346
  normalized_to_remove = set(RoleUtils.normalize_roles(roles_to_remove))
333
-
347
+
334
348
  return [role for role in normalized_roles if role not in normalized_to_remove]
335
-
349
+
336
350
  @staticmethod
337
351
  def is_admin_role(role: str) -> bool:
338
352
  """
339
353
  Check if role is an admin role.
340
-
354
+
341
355
  Args:
342
356
  role: Role to check
343
-
357
+
344
358
  Returns:
345
359
  True if role is admin, False otherwise
346
360
  """
347
361
  if not role:
348
362
  return False
349
-
350
- admin_roles = {'admin', 'administrator', 'root', 'superuser', 'super-admin'}
363
+
364
+ admin_roles = {"admin", "administrator", "root", "superuser", "super-admin"}
351
365
  normalized_role = RoleUtils.normalize_role(role)
352
-
366
+
353
367
  return normalized_role in admin_roles
354
-
368
+
355
369
  @staticmethod
356
370
  def is_system_role(role: str) -> bool:
357
371
  """
358
372
  Check if role is a system role.
359
-
373
+
360
374
  Args:
361
375
  role: Role to check
362
-
376
+
363
377
  Returns:
364
378
  True if role is system role, False otherwise
365
379
  """
366
380
  if not role:
367
381
  return False
368
-
369
- system_roles = {'system', 'service', 'daemon', 'internal', 'system-user'}
382
+
383
+ system_roles = {"system", "service", "daemon", "internal", "system-user"}
370
384
  normalized_role = RoleUtils.normalize_role(role)
371
-
385
+
372
386
  return normalized_role in system_roles
373
-
387
+
374
388
  @staticmethod
375
389
  def get_role_hierarchy(role: str) -> List[str]:
376
390
  """
377
391
  Get role hierarchy (parent roles).
378
-
392
+
379
393
  Args:
380
394
  role: Role to get hierarchy for
381
-
395
+
382
396
  Returns:
383
397
  List of parent roles in hierarchy
384
398
  """
385
399
  if not role:
386
400
  return []
387
-
401
+
388
402
  normalized_role = RoleUtils.normalize_role(role)
389
-
403
+
390
404
  # Define role hierarchy
391
405
  hierarchy = {
392
- 'super-admin': ['admin', 'user'],
393
- 'admin': ['user'],
394
- 'moderator': ['user'],
395
- 'user': [],
396
- 'guest': []
406
+ "super-admin": ["admin", "user"],
407
+ "admin": ["user"],
408
+ "moderator": ["user"],
409
+ "user": [],
410
+ "guest": [],
397
411
  }
398
-
412
+
399
413
  return hierarchy.get(normalized_role, [])
400
-
414
+
401
415
  @staticmethod
402
416
  def get_role_permissions(role: str) -> List[str]:
403
417
  """
404
418
  Get permissions for a role.
405
-
419
+
406
420
  Args:
407
421
  role: Role to get permissions for
408
-
422
+
409
423
  Returns:
410
424
  List of permissions for the role
411
425
  """
412
426
  if not role:
413
427
  return []
414
-
428
+
415
429
  normalized_role = RoleUtils.normalize_role(role)
416
-
430
+
417
431
  # Define role permissions
418
432
  permissions = {
419
- 'super-admin': ['read', 'write', 'delete', 'admin', 'system'],
420
- 'admin': ['read', 'write', 'delete', 'admin'],
421
- 'moderator': ['read', 'write', 'moderate'],
422
- 'user': ['read', 'write'],
423
- 'guest': ['read']
433
+ "super-admin": ["read", "write", "delete", "admin", "system"],
434
+ "admin": ["read", "write", "delete", "admin"],
435
+ "moderator": ["read", "write", "moderate"],
436
+ "user": ["read", "write"],
437
+ "guest": ["read"],
424
438
  }
425
-
426
- return permissions.get(normalized_role, [])
439
+
440
+ return permissions.get(normalized_role, [])