truthound-dashboard 1.3.1__py3-none-any.whl → 1.4.0__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 (169) hide show
  1. truthound_dashboard/api/alerts.py +258 -0
  2. truthound_dashboard/api/anomaly.py +1302 -0
  3. truthound_dashboard/api/cross_alerts.py +352 -0
  4. truthound_dashboard/api/deps.py +143 -0
  5. truthound_dashboard/api/drift_monitor.py +540 -0
  6. truthound_dashboard/api/lineage.py +1151 -0
  7. truthound_dashboard/api/maintenance.py +363 -0
  8. truthound_dashboard/api/middleware.py +373 -1
  9. truthound_dashboard/api/model_monitoring.py +805 -0
  10. truthound_dashboard/api/notifications_advanced.py +2452 -0
  11. truthound_dashboard/api/plugins.py +2096 -0
  12. truthound_dashboard/api/profile.py +211 -14
  13. truthound_dashboard/api/reports.py +853 -0
  14. truthound_dashboard/api/router.py +147 -0
  15. truthound_dashboard/api/rule_suggestions.py +310 -0
  16. truthound_dashboard/api/schema_evolution.py +231 -0
  17. truthound_dashboard/api/sources.py +47 -3
  18. truthound_dashboard/api/triggers.py +190 -0
  19. truthound_dashboard/api/validations.py +13 -0
  20. truthound_dashboard/api/validators.py +333 -4
  21. truthound_dashboard/api/versioning.py +309 -0
  22. truthound_dashboard/api/websocket.py +301 -0
  23. truthound_dashboard/core/__init__.py +27 -0
  24. truthound_dashboard/core/anomaly.py +1395 -0
  25. truthound_dashboard/core/anomaly_explainer.py +633 -0
  26. truthound_dashboard/core/cache.py +206 -0
  27. truthound_dashboard/core/cached_services.py +422 -0
  28. truthound_dashboard/core/charts.py +352 -0
  29. truthound_dashboard/core/connections.py +1069 -42
  30. truthound_dashboard/core/cross_alerts.py +837 -0
  31. truthound_dashboard/core/drift_monitor.py +1477 -0
  32. truthound_dashboard/core/drift_sampling.py +669 -0
  33. truthound_dashboard/core/i18n/__init__.py +42 -0
  34. truthound_dashboard/core/i18n/detector.py +173 -0
  35. truthound_dashboard/core/i18n/messages.py +564 -0
  36. truthound_dashboard/core/lineage.py +971 -0
  37. truthound_dashboard/core/maintenance.py +443 -5
  38. truthound_dashboard/core/model_monitoring.py +1043 -0
  39. truthound_dashboard/core/notifications/channels.py +1020 -1
  40. truthound_dashboard/core/notifications/deduplication/__init__.py +143 -0
  41. truthound_dashboard/core/notifications/deduplication/policies.py +274 -0
  42. truthound_dashboard/core/notifications/deduplication/service.py +400 -0
  43. truthound_dashboard/core/notifications/deduplication/stores.py +2365 -0
  44. truthound_dashboard/core/notifications/deduplication/strategies.py +422 -0
  45. truthound_dashboard/core/notifications/dispatcher.py +43 -0
  46. truthound_dashboard/core/notifications/escalation/__init__.py +149 -0
  47. truthound_dashboard/core/notifications/escalation/backends.py +1384 -0
  48. truthound_dashboard/core/notifications/escalation/engine.py +429 -0
  49. truthound_dashboard/core/notifications/escalation/models.py +336 -0
  50. truthound_dashboard/core/notifications/escalation/scheduler.py +1187 -0
  51. truthound_dashboard/core/notifications/escalation/state_machine.py +330 -0
  52. truthound_dashboard/core/notifications/escalation/stores.py +2896 -0
  53. truthound_dashboard/core/notifications/events.py +49 -0
  54. truthound_dashboard/core/notifications/metrics/__init__.py +115 -0
  55. truthound_dashboard/core/notifications/metrics/base.py +528 -0
  56. truthound_dashboard/core/notifications/metrics/collectors.py +583 -0
  57. truthound_dashboard/core/notifications/routing/__init__.py +169 -0
  58. truthound_dashboard/core/notifications/routing/combinators.py +184 -0
  59. truthound_dashboard/core/notifications/routing/config.py +375 -0
  60. truthound_dashboard/core/notifications/routing/config_parser.py +867 -0
  61. truthound_dashboard/core/notifications/routing/engine.py +382 -0
  62. truthound_dashboard/core/notifications/routing/expression_engine.py +1269 -0
  63. truthound_dashboard/core/notifications/routing/jinja2_engine.py +774 -0
  64. truthound_dashboard/core/notifications/routing/rules.py +625 -0
  65. truthound_dashboard/core/notifications/routing/validator.py +678 -0
  66. truthound_dashboard/core/notifications/service.py +2 -0
  67. truthound_dashboard/core/notifications/stats_aggregator.py +850 -0
  68. truthound_dashboard/core/notifications/throttling/__init__.py +83 -0
  69. truthound_dashboard/core/notifications/throttling/builder.py +311 -0
  70. truthound_dashboard/core/notifications/throttling/stores.py +1859 -0
  71. truthound_dashboard/core/notifications/throttling/throttlers.py +633 -0
  72. truthound_dashboard/core/openlineage.py +1028 -0
  73. truthound_dashboard/core/plugins/__init__.py +39 -0
  74. truthound_dashboard/core/plugins/docs/__init__.py +39 -0
  75. truthound_dashboard/core/plugins/docs/extractor.py +703 -0
  76. truthound_dashboard/core/plugins/docs/renderers.py +804 -0
  77. truthound_dashboard/core/plugins/hooks/__init__.py +63 -0
  78. truthound_dashboard/core/plugins/hooks/decorators.py +367 -0
  79. truthound_dashboard/core/plugins/hooks/manager.py +403 -0
  80. truthound_dashboard/core/plugins/hooks/protocols.py +265 -0
  81. truthound_dashboard/core/plugins/lifecycle/__init__.py +41 -0
  82. truthound_dashboard/core/plugins/lifecycle/hot_reload.py +584 -0
  83. truthound_dashboard/core/plugins/lifecycle/machine.py +419 -0
  84. truthound_dashboard/core/plugins/lifecycle/states.py +266 -0
  85. truthound_dashboard/core/plugins/loader.py +504 -0
  86. truthound_dashboard/core/plugins/registry.py +810 -0
  87. truthound_dashboard/core/plugins/reporter_executor.py +588 -0
  88. truthound_dashboard/core/plugins/sandbox/__init__.py +59 -0
  89. truthound_dashboard/core/plugins/sandbox/code_validator.py +243 -0
  90. truthound_dashboard/core/plugins/sandbox/engines.py +770 -0
  91. truthound_dashboard/core/plugins/sandbox/protocols.py +194 -0
  92. truthound_dashboard/core/plugins/sandbox.py +617 -0
  93. truthound_dashboard/core/plugins/security/__init__.py +68 -0
  94. truthound_dashboard/core/plugins/security/analyzer.py +535 -0
  95. truthound_dashboard/core/plugins/security/policies.py +311 -0
  96. truthound_dashboard/core/plugins/security/protocols.py +296 -0
  97. truthound_dashboard/core/plugins/security/signing.py +842 -0
  98. truthound_dashboard/core/plugins/security.py +446 -0
  99. truthound_dashboard/core/plugins/validator_executor.py +401 -0
  100. truthound_dashboard/core/plugins/versioning/__init__.py +51 -0
  101. truthound_dashboard/core/plugins/versioning/constraints.py +377 -0
  102. truthound_dashboard/core/plugins/versioning/dependencies.py +541 -0
  103. truthound_dashboard/core/plugins/versioning/semver.py +266 -0
  104. truthound_dashboard/core/profile_comparison.py +601 -0
  105. truthound_dashboard/core/report_history.py +570 -0
  106. truthound_dashboard/core/reporters/__init__.py +57 -0
  107. truthound_dashboard/core/reporters/base.py +296 -0
  108. truthound_dashboard/core/reporters/csv_reporter.py +155 -0
  109. truthound_dashboard/core/reporters/html_reporter.py +598 -0
  110. truthound_dashboard/core/reporters/i18n/__init__.py +65 -0
  111. truthound_dashboard/core/reporters/i18n/base.py +494 -0
  112. truthound_dashboard/core/reporters/i18n/catalogs.py +930 -0
  113. truthound_dashboard/core/reporters/json_reporter.py +160 -0
  114. truthound_dashboard/core/reporters/junit_reporter.py +233 -0
  115. truthound_dashboard/core/reporters/markdown_reporter.py +207 -0
  116. truthound_dashboard/core/reporters/pdf_reporter.py +209 -0
  117. truthound_dashboard/core/reporters/registry.py +272 -0
  118. truthound_dashboard/core/rule_generator.py +2088 -0
  119. truthound_dashboard/core/scheduler.py +822 -12
  120. truthound_dashboard/core/schema_evolution.py +858 -0
  121. truthound_dashboard/core/services.py +152 -9
  122. truthound_dashboard/core/statistics.py +718 -0
  123. truthound_dashboard/core/streaming_anomaly.py +883 -0
  124. truthound_dashboard/core/triggers/__init__.py +45 -0
  125. truthound_dashboard/core/triggers/base.py +226 -0
  126. truthound_dashboard/core/triggers/evaluators.py +609 -0
  127. truthound_dashboard/core/triggers/factory.py +363 -0
  128. truthound_dashboard/core/unified_alerts.py +870 -0
  129. truthound_dashboard/core/validation_limits.py +509 -0
  130. truthound_dashboard/core/versioning.py +709 -0
  131. truthound_dashboard/core/websocket/__init__.py +59 -0
  132. truthound_dashboard/core/websocket/manager.py +512 -0
  133. truthound_dashboard/core/websocket/messages.py +130 -0
  134. truthound_dashboard/db/__init__.py +30 -0
  135. truthound_dashboard/db/models.py +3375 -3
  136. truthound_dashboard/main.py +22 -0
  137. truthound_dashboard/schemas/__init__.py +396 -1
  138. truthound_dashboard/schemas/anomaly.py +1258 -0
  139. truthound_dashboard/schemas/base.py +4 -0
  140. truthound_dashboard/schemas/cross_alerts.py +334 -0
  141. truthound_dashboard/schemas/drift_monitor.py +890 -0
  142. truthound_dashboard/schemas/lineage.py +428 -0
  143. truthound_dashboard/schemas/maintenance.py +154 -0
  144. truthound_dashboard/schemas/model_monitoring.py +374 -0
  145. truthound_dashboard/schemas/notifications_advanced.py +1363 -0
  146. truthound_dashboard/schemas/openlineage.py +704 -0
  147. truthound_dashboard/schemas/plugins.py +1293 -0
  148. truthound_dashboard/schemas/profile.py +420 -34
  149. truthound_dashboard/schemas/profile_comparison.py +242 -0
  150. truthound_dashboard/schemas/reports.py +285 -0
  151. truthound_dashboard/schemas/rule_suggestion.py +434 -0
  152. truthound_dashboard/schemas/schema_evolution.py +164 -0
  153. truthound_dashboard/schemas/source.py +117 -2
  154. truthound_dashboard/schemas/triggers.py +511 -0
  155. truthound_dashboard/schemas/unified_alerts.py +223 -0
  156. truthound_dashboard/schemas/validation.py +25 -1
  157. truthound_dashboard/schemas/validators/__init__.py +11 -0
  158. truthound_dashboard/schemas/validators/base.py +151 -0
  159. truthound_dashboard/schemas/versioning.py +152 -0
  160. truthound_dashboard/static/index.html +2 -2
  161. {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/METADATA +142 -22
  162. truthound_dashboard-1.4.0.dist-info/RECORD +239 -0
  163. truthound_dashboard/static/assets/index-BZG20KuF.js +0 -586
  164. truthound_dashboard/static/assets/index-D_HyZ3pb.css +0 -1
  165. truthound_dashboard/static/assets/unmerged_dictionaries-CtpqQBm0.js +0 -1
  166. truthound_dashboard-1.3.1.dist-info/RECORD +0 -110
  167. {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/WHEEL +0 -0
  168. {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/entry_points.txt +0 -0
  169. {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,446 @@
1
+ """Plugin Security Management.
2
+
3
+ This module provides security features for plugins:
4
+ - Signature verification
5
+ - Permission management
6
+ - Security analysis
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import hashlib
12
+ import hmac
13
+ import logging
14
+ from dataclasses import dataclass, field
15
+ from datetime import datetime
16
+ from typing import Any
17
+
18
+ from .sandbox import CodeAnalyzer, SandboxConfig
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ @dataclass
24
+ class SecurityReport:
25
+ """Security analysis report for a plugin.
26
+
27
+ Attributes:
28
+ plugin_id: Plugin identifier.
29
+ analyzed_at: When analysis was performed.
30
+ risk_level: Overall risk level.
31
+ signature_valid: Whether signature is valid.
32
+ sandbox_compatible: Whether code can run in sandbox.
33
+ issues: Critical security issues found.
34
+ warnings: Non-critical warnings.
35
+ permissions_required: Required permissions.
36
+ code_hash: Hash of analyzed code.
37
+ """
38
+
39
+ plugin_id: str
40
+ analyzed_at: datetime
41
+ risk_level: str # trusted, verified, unverified, sandboxed
42
+ signature_valid: bool = False
43
+ sandbox_compatible: bool = True
44
+ issues: list[str] = field(default_factory=list)
45
+ warnings: list[str] = field(default_factory=list)
46
+ permissions_required: list[str] = field(default_factory=list)
47
+ code_hash: str = ""
48
+
49
+ def is_safe(self) -> bool:
50
+ """Check if plugin is considered safe.
51
+
52
+ Returns:
53
+ True if no critical issues and sandbox compatible.
54
+ """
55
+ return len(self.issues) == 0 and self.sandbox_compatible
56
+
57
+
58
+ class SignatureVerifier:
59
+ """Verifies plugin signatures.
60
+
61
+ This class handles cryptographic verification of plugin
62
+ packages to ensure authenticity and integrity.
63
+
64
+ Attributes:
65
+ trusted_keys: Dictionary of trusted public keys by key ID.
66
+ """
67
+
68
+ def __init__(self, trusted_keys: dict[str, str] | None = None) -> None:
69
+ """Initialize the verifier.
70
+
71
+ Args:
72
+ trusted_keys: Dictionary mapping key IDs to public keys.
73
+ """
74
+ self.trusted_keys = trusted_keys or {}
75
+
76
+ def add_trusted_key(self, key_id: str, public_key: str) -> None:
77
+ """Add a trusted public key.
78
+
79
+ Args:
80
+ key_id: Key identifier.
81
+ public_key: Public key (hex encoded).
82
+ """
83
+ self.trusted_keys[key_id] = public_key
84
+ logger.info(f"Added trusted key: {key_id}")
85
+
86
+ def remove_trusted_key(self, key_id: str) -> None:
87
+ """Remove a trusted public key.
88
+
89
+ Args:
90
+ key_id: Key identifier.
91
+ """
92
+ if key_id in self.trusted_keys:
93
+ del self.trusted_keys[key_id]
94
+ logger.info(f"Removed trusted key: {key_id}")
95
+
96
+ def verify_hmac(
97
+ self,
98
+ data: bytes,
99
+ signature: str,
100
+ secret_key: str,
101
+ ) -> bool:
102
+ """Verify HMAC signature.
103
+
104
+ Args:
105
+ data: Data that was signed.
106
+ signature: HMAC signature (hex encoded).
107
+ secret_key: Secret key for HMAC.
108
+
109
+ Returns:
110
+ True if signature is valid.
111
+ """
112
+ try:
113
+ expected = hmac.new(
114
+ secret_key.encode(),
115
+ data,
116
+ hashlib.sha256,
117
+ ).hexdigest()
118
+ return hmac.compare_digest(expected, signature)
119
+ except Exception as e:
120
+ logger.warning(f"HMAC verification failed: {e}")
121
+ return False
122
+
123
+ def verify_signature(
124
+ self,
125
+ data: bytes,
126
+ signature: str,
127
+ key_id: str | None = None,
128
+ ) -> tuple[bool, str | None]:
129
+ """Verify a signature.
130
+
131
+ Args:
132
+ data: Data that was signed.
133
+ signature: Signature (format depends on algorithm).
134
+ key_id: Optional key ID to use.
135
+
136
+ Returns:
137
+ Tuple of (is_valid, error_message).
138
+ """
139
+ if not signature:
140
+ return False, "No signature provided"
141
+
142
+ # For now, use simple HMAC verification
143
+ # In production, you would use proper asymmetric cryptography
144
+ # like Ed25519 or RSA
145
+
146
+ if key_id and key_id in self.trusted_keys:
147
+ key = self.trusted_keys[key_id]
148
+ if self.verify_hmac(data, signature, key):
149
+ return True, None
150
+ return False, "Signature verification failed"
151
+
152
+ # Try all trusted keys
153
+ for kid, key in self.trusted_keys.items():
154
+ if self.verify_hmac(data, signature, key):
155
+ return True, None
156
+
157
+ return False, "No matching trusted key found"
158
+
159
+ def create_signature(
160
+ self,
161
+ data: bytes,
162
+ secret_key: str,
163
+ ) -> str:
164
+ """Create a signature for data.
165
+
166
+ Args:
167
+ data: Data to sign.
168
+ secret_key: Secret key for signing.
169
+
170
+ Returns:
171
+ Signature (hex encoded).
172
+ """
173
+ return hmac.new(
174
+ secret_key.encode(),
175
+ data,
176
+ hashlib.sha256,
177
+ ).hexdigest()
178
+
179
+
180
+ class PluginSecurityManager:
181
+ """Manages security for plugins.
182
+
183
+ This class provides comprehensive security analysis
184
+ and management for plugins.
185
+
186
+ Attributes:
187
+ signature_verifier: Signature verifier instance.
188
+ sandbox_config: Default sandbox configuration.
189
+ """
190
+
191
+ def __init__(
192
+ self,
193
+ signature_verifier: SignatureVerifier | None = None,
194
+ sandbox_config: SandboxConfig | None = None,
195
+ ) -> None:
196
+ """Initialize the security manager.
197
+
198
+ Args:
199
+ signature_verifier: Signature verifier.
200
+ sandbox_config: Default sandbox configuration.
201
+ """
202
+ self.signature_verifier = signature_verifier or SignatureVerifier()
203
+ self.sandbox_config = sandbox_config or SandboxConfig()
204
+
205
+ def analyze_code(self, code: str) -> tuple[list[str], list[str]]:
206
+ """Analyze code for security issues.
207
+
208
+ Args:
209
+ code: Python source code.
210
+
211
+ Returns:
212
+ Tuple of (issues, warnings).
213
+ """
214
+ analyzer = CodeAnalyzer()
215
+ return analyzer.analyze(code)
216
+
217
+ def detect_permissions(self, code: str) -> list[str]:
218
+ """Detect required permissions from code.
219
+
220
+ Args:
221
+ code: Python source code.
222
+
223
+ Returns:
224
+ List of required permission strings.
225
+ """
226
+ import ast
227
+
228
+ permissions = set()
229
+
230
+ try:
231
+ tree = ast.parse(code)
232
+
233
+ for node in ast.walk(tree):
234
+ # Check imports
235
+ if isinstance(node, (ast.Import, ast.ImportFrom)):
236
+ module = getattr(node, "module", None)
237
+ if module:
238
+ modules = [module]
239
+ else:
240
+ modules = [alias.name for alias in node.names]
241
+
242
+ for mod in modules:
243
+ if mod.startswith(("http", "urllib", "requests", "httpx", "socket")):
244
+ permissions.add("network_access")
245
+ elif mod.startswith(("os", "shutil", "pathlib")):
246
+ permissions.add("file_system")
247
+ elif mod.startswith(("subprocess", "multiprocessing")):
248
+ permissions.add("execute_code")
249
+ elif mod.startswith(("pickle", "shelve")):
250
+ permissions.add("read_data")
251
+ permissions.add("write_data")
252
+
253
+ # Check for file operations
254
+ if isinstance(node, ast.Call):
255
+ if isinstance(node.func, ast.Name):
256
+ if node.func.id == "open":
257
+ permissions.add("file_system")
258
+
259
+ except SyntaxError:
260
+ pass
261
+
262
+ return sorted(list(permissions))
263
+
264
+ def analyze_plugin(
265
+ self,
266
+ plugin_id: str,
267
+ code: str,
268
+ signature: str | None = None,
269
+ package_data: bytes | None = None,
270
+ ) -> SecurityReport:
271
+ """Perform security analysis on a plugin.
272
+
273
+ Args:
274
+ plugin_id: Plugin identifier.
275
+ code: Plugin code to analyze.
276
+ signature: Optional signature to verify.
277
+ package_data: Optional package data for signature verification.
278
+
279
+ Returns:
280
+ SecurityReport with analysis results.
281
+ """
282
+ issues, warnings = self.analyze_code(code)
283
+ permissions = self.detect_permissions(code)
284
+ code_hash = hashlib.sha256(code.encode()).hexdigest()
285
+
286
+ # Verify signature if provided
287
+ signature_valid = False
288
+ if signature and package_data:
289
+ signature_valid, _ = self.signature_verifier.verify_signature(
290
+ package_data, signature
291
+ )
292
+ elif signature and code:
293
+ signature_valid, _ = self.signature_verifier.verify_signature(
294
+ code.encode(), signature
295
+ )
296
+
297
+ # Determine risk level
298
+ if signature_valid:
299
+ if not issues:
300
+ risk_level = "trusted"
301
+ else:
302
+ risk_level = "verified"
303
+ else:
304
+ if issues:
305
+ risk_level = "sandboxed"
306
+ else:
307
+ risk_level = "unverified"
308
+
309
+ # Check sandbox compatibility
310
+ sandbox_compatible = self._check_sandbox_compatible(code, issues)
311
+
312
+ return SecurityReport(
313
+ plugin_id=plugin_id,
314
+ analyzed_at=datetime.utcnow(),
315
+ risk_level=risk_level,
316
+ signature_valid=signature_valid,
317
+ sandbox_compatible=sandbox_compatible,
318
+ issues=issues,
319
+ warnings=warnings,
320
+ permissions_required=permissions,
321
+ code_hash=code_hash,
322
+ )
323
+
324
+ def _check_sandbox_compatible(
325
+ self,
326
+ code: str,
327
+ issues: list[str],
328
+ ) -> bool:
329
+ """Check if code is compatible with sandbox execution.
330
+
331
+ Args:
332
+ code: Python source code.
333
+ issues: Already detected issues.
334
+
335
+ Returns:
336
+ True if code can run in sandbox.
337
+ """
338
+ # If there are critical issues, might not be compatible
339
+ if any("blocked" in issue.lower() for issue in issues):
340
+ return False
341
+
342
+ # Check for patterns that won't work in sandbox
343
+ dangerous_patterns = [
344
+ "__import__",
345
+ "importlib",
346
+ "sys.modules",
347
+ "globals()",
348
+ "locals()",
349
+ "__class__.__bases__",
350
+ "__subclasses__",
351
+ ]
352
+
353
+ for pattern in dangerous_patterns:
354
+ if pattern in code:
355
+ return False
356
+
357
+ return True
358
+
359
+ def validate_permissions(
360
+ self,
361
+ required: list[str],
362
+ granted: list[str],
363
+ ) -> tuple[bool, list[str]]:
364
+ """Validate that required permissions are granted.
365
+
366
+ Args:
367
+ required: Required permissions.
368
+ granted: Granted permissions.
369
+
370
+ Returns:
371
+ Tuple of (all_granted, missing_permissions).
372
+ """
373
+ granted_set = set(granted)
374
+ missing = [p for p in required if p not in granted_set]
375
+ return len(missing) == 0, missing
376
+
377
+ def get_security_level(
378
+ self,
379
+ report: SecurityReport,
380
+ user_trust_level: str = "normal",
381
+ ) -> str:
382
+ """Determine final security level based on analysis and trust.
383
+
384
+ Args:
385
+ report: Security analysis report.
386
+ user_trust_level: User's trust level (admin, normal, restricted).
387
+
388
+ Returns:
389
+ Final security level recommendation.
390
+ """
391
+ if user_trust_level == "admin":
392
+ # Admins can run anything
393
+ return report.risk_level
394
+
395
+ if user_trust_level == "restricted":
396
+ # Restricted users can only run trusted plugins
397
+ if report.risk_level != "trusted":
398
+ return "sandboxed"
399
+ return report.risk_level
400
+
401
+ # Normal users
402
+ if report.issues:
403
+ return "sandboxed"
404
+
405
+ return report.risk_level
406
+
407
+ def create_sandbox_config_for_plugin(
408
+ self,
409
+ report: SecurityReport,
410
+ base_config: SandboxConfig | None = None,
411
+ ) -> SandboxConfig:
412
+ """Create appropriate sandbox config based on security analysis.
413
+
414
+ Args:
415
+ report: Security analysis report.
416
+ base_config: Base configuration to modify.
417
+
418
+ Returns:
419
+ Configured SandboxConfig.
420
+ """
421
+ config = base_config or SandboxConfig()
422
+
423
+ # Adjust based on risk level
424
+ if report.risk_level == "trusted":
425
+ # Trusted plugins get more freedom
426
+ config.enabled = False
427
+ elif report.risk_level == "verified":
428
+ # Verified plugins get relaxed restrictions
429
+ config.memory_limit_mb = 512
430
+ config.cpu_time_limit_seconds = 60
431
+ config.network_enabled = "network_access" in report.permissions_required
432
+ elif report.risk_level == "unverified":
433
+ # Default restrictions
434
+ config.enabled = True
435
+ else: # sandboxed
436
+ # Strict restrictions
437
+ config.memory_limit_mb = 128
438
+ config.cpu_time_limit_seconds = 15
439
+ config.network_enabled = False
440
+
441
+ return config
442
+
443
+
444
+ # Default instances
445
+ signature_verifier = SignatureVerifier()
446
+ security_manager = PluginSecurityManager(signature_verifier)