truthound-dashboard 1.3.1__py3-none-any.whl → 1.4.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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.1.dist-info}/METADATA +147 -23
  162. truthound_dashboard-1.4.1.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.1.dist-info}/WHEEL +0 -0
  168. {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.1.dist-info}/entry_points.txt +0 -0
  169. {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,311 @@
1
+ """Security Policy Presets.
2
+
3
+ This module provides predefined security policies for different
4
+ use cases and environments.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from enum import Enum
10
+ from typing import Any
11
+
12
+ from .protocols import (
13
+ IsolationLevel,
14
+ ResourceLimits,
15
+ SecurityPolicy,
16
+ )
17
+
18
+
19
+ class SecurityPolicyPresets(str, Enum):
20
+ """Predefined security policy presets."""
21
+
22
+ DEVELOPMENT = "development" # No restrictions, for local dev
23
+ TESTING = "testing" # Minimal restrictions for testing
24
+ STANDARD = "standard" # Default production settings
25
+ ENTERPRISE = "enterprise" # Enterprise security requirements
26
+ STRICT = "strict" # High security environment
27
+ AIRGAPPED = "airgapped" # Air-gapped/isolated environment
28
+
29
+
30
+ # Policy definitions
31
+ _PRESET_POLICIES: dict[SecurityPolicyPresets, SecurityPolicy] = {
32
+ SecurityPolicyPresets.DEVELOPMENT: SecurityPolicy(
33
+ name="development",
34
+ description="Development mode with minimal restrictions",
35
+ isolation_level=IsolationLevel.NONE,
36
+ resource_limits=ResourceLimits(
37
+ max_memory_mb=1024,
38
+ max_cpu_time_sec=300,
39
+ max_wall_time_sec=600,
40
+ max_file_size_mb=100,
41
+ max_open_files=100,
42
+ max_processes=10,
43
+ network_enabled=True,
44
+ filesystem_read=True,
45
+ filesystem_write=True,
46
+ ),
47
+ require_signature=False,
48
+ min_signatures=0,
49
+ blocked_modules=[],
50
+ ),
51
+ SecurityPolicyPresets.TESTING: SecurityPolicy(
52
+ name="testing",
53
+ description="Testing mode with relaxed restrictions",
54
+ isolation_level=IsolationLevel.NONE,
55
+ resource_limits=ResourceLimits(
56
+ max_memory_mb=512,
57
+ max_cpu_time_sec=120,
58
+ max_wall_time_sec=300,
59
+ max_file_size_mb=50,
60
+ max_open_files=50,
61
+ max_processes=5,
62
+ network_enabled=True,
63
+ filesystem_read=True,
64
+ filesystem_write=True,
65
+ ),
66
+ require_signature=False,
67
+ min_signatures=0,
68
+ blocked_modules=[],
69
+ ),
70
+ SecurityPolicyPresets.STANDARD: SecurityPolicy(
71
+ name="standard",
72
+ description="Standard production security",
73
+ isolation_level=IsolationLevel.PROCESS,
74
+ resource_limits=ResourceLimits(
75
+ max_memory_mb=256,
76
+ max_cpu_time_sec=30,
77
+ max_wall_time_sec=60,
78
+ max_file_size_mb=10,
79
+ max_open_files=10,
80
+ max_processes=1,
81
+ network_enabled=False,
82
+ filesystem_read=False,
83
+ filesystem_write=False,
84
+ ),
85
+ require_signature=True,
86
+ min_signatures=1,
87
+ blocked_modules=[
88
+ "os", "subprocess", "sys", "shutil", "socket",
89
+ "http", "urllib", "requests", "httpx",
90
+ "multiprocessing", "threading", "ctypes",
91
+ "pickle", "shelve", "sqlite3", "importlib",
92
+ ],
93
+ ),
94
+ SecurityPolicyPresets.ENTERPRISE: SecurityPolicy(
95
+ name="enterprise",
96
+ description="Enterprise security with signature requirements",
97
+ isolation_level=IsolationLevel.PROCESS,
98
+ resource_limits=ResourceLimits(
99
+ max_memory_mb=256,
100
+ max_cpu_time_sec=30,
101
+ max_wall_time_sec=60,
102
+ max_file_size_mb=10,
103
+ max_open_files=10,
104
+ max_processes=1,
105
+ network_enabled=False,
106
+ filesystem_read=False,
107
+ filesystem_write=False,
108
+ ),
109
+ require_signature=True,
110
+ min_signatures=1,
111
+ blocked_modules=[
112
+ "os", "subprocess", "sys", "shutil", "socket",
113
+ "http", "urllib", "requests", "httpx",
114
+ "multiprocessing", "threading", "ctypes",
115
+ "pickle", "shelve", "sqlite3", "importlib",
116
+ "builtins", "__builtin__",
117
+ ],
118
+ ),
119
+ SecurityPolicyPresets.STRICT: SecurityPolicy(
120
+ name="strict",
121
+ description="High security environment with container isolation",
122
+ isolation_level=IsolationLevel.CONTAINER,
123
+ resource_limits=ResourceLimits(
124
+ max_memory_mb=128,
125
+ max_cpu_time_sec=15,
126
+ max_wall_time_sec=30,
127
+ max_file_size_mb=5,
128
+ max_open_files=5,
129
+ max_processes=1,
130
+ network_enabled=False,
131
+ filesystem_read=False,
132
+ filesystem_write=False,
133
+ ),
134
+ require_signature=True,
135
+ min_signatures=2,
136
+ blocked_modules=[
137
+ "os", "subprocess", "sys", "shutil", "socket",
138
+ "http", "urllib", "requests", "httpx",
139
+ "multiprocessing", "threading", "ctypes",
140
+ "pickle", "shelve", "sqlite3", "importlib",
141
+ "builtins", "__builtin__", "code", "codeop",
142
+ "gc", "inspect", "traceback",
143
+ ],
144
+ ),
145
+ SecurityPolicyPresets.AIRGAPPED: SecurityPolicy(
146
+ name="airgapped",
147
+ description="Air-gapped environment with maximum restrictions",
148
+ isolation_level=IsolationLevel.CONTAINER,
149
+ resource_limits=ResourceLimits(
150
+ max_memory_mb=64,
151
+ max_cpu_time_sec=10,
152
+ max_wall_time_sec=20,
153
+ max_file_size_mb=1,
154
+ max_open_files=3,
155
+ max_processes=1,
156
+ network_enabled=False,
157
+ filesystem_read=False,
158
+ filesystem_write=False,
159
+ ),
160
+ require_signature=True,
161
+ min_signatures=2,
162
+ blocked_modules=[
163
+ "os", "subprocess", "sys", "shutil", "socket",
164
+ "http", "urllib", "requests", "httpx",
165
+ "multiprocessing", "threading", "ctypes",
166
+ "pickle", "shelve", "sqlite3", "importlib",
167
+ "builtins", "__builtin__", "code", "codeop",
168
+ "gc", "inspect", "traceback", "ast", "dis",
169
+ "types", "typing", "io", "tempfile",
170
+ ],
171
+ ),
172
+ }
173
+
174
+
175
+ def get_preset(preset: SecurityPolicyPresets | str) -> SecurityPolicy:
176
+ """Get a security policy preset.
177
+
178
+ Args:
179
+ preset: Preset name or enum value.
180
+
181
+ Returns:
182
+ SecurityPolicy for the preset.
183
+
184
+ Raises:
185
+ ValueError: If preset is not found.
186
+ """
187
+ if isinstance(preset, str):
188
+ try:
189
+ preset = SecurityPolicyPresets(preset)
190
+ except ValueError:
191
+ raise ValueError(f"Unknown security preset: {preset}")
192
+
193
+ if preset not in _PRESET_POLICIES:
194
+ raise ValueError(f"Unknown security preset: {preset}")
195
+
196
+ # Return a copy to prevent modification
197
+ original = _PRESET_POLICIES[preset]
198
+ return SecurityPolicy(
199
+ name=original.name,
200
+ description=original.description,
201
+ isolation_level=original.isolation_level,
202
+ resource_limits=ResourceLimits(
203
+ max_memory_mb=original.resource_limits.max_memory_mb,
204
+ max_cpu_time_sec=original.resource_limits.max_cpu_time_sec,
205
+ max_wall_time_sec=original.resource_limits.max_wall_time_sec,
206
+ max_file_size_mb=original.resource_limits.max_file_size_mb,
207
+ max_open_files=original.resource_limits.max_open_files,
208
+ max_processes=original.resource_limits.max_processes,
209
+ network_enabled=original.resource_limits.network_enabled,
210
+ filesystem_read=original.resource_limits.filesystem_read,
211
+ filesystem_write=original.resource_limits.filesystem_write,
212
+ ),
213
+ require_signature=original.require_signature,
214
+ min_signatures=original.min_signatures,
215
+ allowed_signers=original.allowed_signers.copy(),
216
+ blocked_modules=original.blocked_modules.copy(),
217
+ allowed_permissions=original.allowed_permissions.copy(),
218
+ )
219
+
220
+
221
+ def list_presets() -> list[dict[str, Any]]:
222
+ """List all available security presets.
223
+
224
+ Returns:
225
+ List of preset information dictionaries.
226
+ """
227
+ return [
228
+ {
229
+ "name": preset.value,
230
+ "description": _PRESET_POLICIES[preset].description,
231
+ "isolation_level": _PRESET_POLICIES[preset].isolation_level.value,
232
+ "require_signature": _PRESET_POLICIES[preset].require_signature,
233
+ "min_signatures": _PRESET_POLICIES[preset].min_signatures,
234
+ }
235
+ for preset in SecurityPolicyPresets
236
+ ]
237
+
238
+
239
+ def create_policy(
240
+ preset: SecurityPolicyPresets | str = SecurityPolicyPresets.STANDARD,
241
+ *,
242
+ isolation_level: IsolationLevel | str | None = None,
243
+ max_memory_mb: int | None = None,
244
+ max_cpu_time_sec: int | None = None,
245
+ max_wall_time_sec: int | None = None,
246
+ network_enabled: bool | None = None,
247
+ filesystem_read: bool | None = None,
248
+ filesystem_write: bool | None = None,
249
+ require_signature: bool | None = None,
250
+ min_signatures: int | None = None,
251
+ allowed_signers: list[str] | None = None,
252
+ blocked_modules: list[str] | None = None,
253
+ allowed_permissions: list[str] | None = None,
254
+ ) -> SecurityPolicy:
255
+ """Create a customized security policy based on a preset.
256
+
257
+ Args:
258
+ preset: Base preset to customize.
259
+ isolation_level: Override isolation level.
260
+ max_memory_mb: Override memory limit.
261
+ max_cpu_time_sec: Override CPU time limit.
262
+ max_wall_time_sec: Override wall time limit.
263
+ network_enabled: Override network access.
264
+ filesystem_read: Override filesystem read.
265
+ filesystem_write: Override filesystem write.
266
+ require_signature: Override signature requirement.
267
+ min_signatures: Override minimum signatures.
268
+ allowed_signers: Override allowed signers.
269
+ blocked_modules: Override blocked modules.
270
+ allowed_permissions: Override allowed permissions.
271
+
272
+ Returns:
273
+ Customized SecurityPolicy.
274
+ """
275
+ policy = get_preset(preset)
276
+
277
+ # Override isolation level
278
+ if isolation_level is not None:
279
+ if isinstance(isolation_level, str):
280
+ isolation_level = IsolationLevel(isolation_level)
281
+ policy.isolation_level = isolation_level
282
+
283
+ # Override resource limits
284
+ if max_memory_mb is not None:
285
+ policy.resource_limits.max_memory_mb = max_memory_mb
286
+ if max_cpu_time_sec is not None:
287
+ policy.resource_limits.max_cpu_time_sec = max_cpu_time_sec
288
+ if max_wall_time_sec is not None:
289
+ policy.resource_limits.max_wall_time_sec = max_wall_time_sec
290
+ if network_enabled is not None:
291
+ policy.resource_limits.network_enabled = network_enabled
292
+ if filesystem_read is not None:
293
+ policy.resource_limits.filesystem_read = filesystem_read
294
+ if filesystem_write is not None:
295
+ policy.resource_limits.filesystem_write = filesystem_write
296
+
297
+ # Override signature requirements
298
+ if require_signature is not None:
299
+ policy.require_signature = require_signature
300
+ if min_signatures is not None:
301
+ policy.min_signatures = min_signatures
302
+ if allowed_signers is not None:
303
+ policy.allowed_signers = allowed_signers
304
+
305
+ # Override module restrictions
306
+ if blocked_modules is not None:
307
+ policy.blocked_modules = blocked_modules
308
+ if allowed_permissions is not None:
309
+ policy.allowed_permissions = allowed_permissions
310
+
311
+ return policy
@@ -0,0 +1,296 @@
1
+ """Security Protocol Definitions.
2
+
3
+ This module defines the core protocols and data types for the
4
+ enterprise plugin security system.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass, field
10
+ from datetime import datetime
11
+ from enum import Enum
12
+ from typing import Any, Protocol
13
+
14
+
15
+ class IsolationLevel(str, Enum):
16
+ """Sandbox isolation levels."""
17
+
18
+ NONE = "none" # No isolation (trusted plugins only)
19
+ PROCESS = "process" # Subprocess isolation with resource limits
20
+ CONTAINER = "container" # Docker/Podman container isolation
21
+
22
+
23
+ class TrustLevel(str, Enum):
24
+ """Plugin trust levels."""
25
+
26
+ TRUSTED = "trusted" # Signed by trusted authority, no issues
27
+ VERIFIED = "verified" # Signature valid but has warnings
28
+ UNVERIFIED = "unverified" # No signature or invalid
29
+ SANDBOXED = "sandboxed" # Must run in sandbox due to issues
30
+
31
+
32
+ class SignatureAlgorithm(str, Enum):
33
+ """Supported signature algorithms."""
34
+
35
+ SHA256 = "sha256" # Simple hash (integrity only)
36
+ SHA512 = "sha512" # Simple hash (integrity only)
37
+ HMAC_SHA256 = "hmac_sha256" # Symmetric key
38
+ HMAC_SHA512 = "hmac_sha512" # Symmetric key
39
+ RSA_SHA256 = "rsa_sha256" # Asymmetric (public key)
40
+ ED25519 = "ed25519" # Modern asymmetric (recommended)
41
+
42
+
43
+ @dataclass
44
+ class ResourceLimits:
45
+ """Resource limits for sandbox execution.
46
+
47
+ Attributes:
48
+ max_memory_mb: Maximum memory in megabytes.
49
+ max_cpu_time_sec: Maximum CPU time in seconds.
50
+ max_wall_time_sec: Maximum wall clock time in seconds.
51
+ max_file_size_mb: Maximum file size in megabytes.
52
+ max_open_files: Maximum number of open files.
53
+ max_processes: Maximum number of processes.
54
+ network_enabled: Whether network access is allowed.
55
+ filesystem_read: Whether filesystem read is allowed.
56
+ filesystem_write: Whether filesystem write is allowed.
57
+ """
58
+
59
+ max_memory_mb: int = 256
60
+ max_cpu_time_sec: int = 30
61
+ max_wall_time_sec: int = 60
62
+ max_file_size_mb: int = 10
63
+ max_open_files: int = 10
64
+ max_processes: int = 1
65
+ network_enabled: bool = False
66
+ filesystem_read: bool = False
67
+ filesystem_write: bool = False
68
+
69
+
70
+ @dataclass
71
+ class SecurityPolicy:
72
+ """Security policy configuration.
73
+
74
+ Attributes:
75
+ name: Policy name.
76
+ description: Policy description.
77
+ isolation_level: Required isolation level.
78
+ resource_limits: Resource limits.
79
+ require_signature: Whether signature is required.
80
+ min_signatures: Minimum number of valid signatures.
81
+ allowed_signers: List of allowed signer IDs (empty = any).
82
+ blocked_modules: Blocked Python modules.
83
+ allowed_permissions: Allowed permission types.
84
+ """
85
+
86
+ name: str
87
+ description: str = ""
88
+ isolation_level: IsolationLevel = IsolationLevel.PROCESS
89
+ resource_limits: ResourceLimits = field(default_factory=ResourceLimits)
90
+ require_signature: bool = False
91
+ min_signatures: int = 0
92
+ allowed_signers: list[str] = field(default_factory=list)
93
+ blocked_modules: list[str] = field(default_factory=lambda: [
94
+ "os", "subprocess", "sys", "shutil", "socket",
95
+ "http", "urllib", "requests", "httpx",
96
+ "multiprocessing", "threading", "ctypes",
97
+ "pickle", "shelve", "sqlite3", "importlib",
98
+ ])
99
+ allowed_permissions: list[str] = field(default_factory=list)
100
+
101
+ def to_dict(self) -> dict[str, Any]:
102
+ """Convert to dictionary."""
103
+ return {
104
+ "name": self.name,
105
+ "description": self.description,
106
+ "isolation_level": self.isolation_level.value,
107
+ "resource_limits": {
108
+ "max_memory_mb": self.resource_limits.max_memory_mb,
109
+ "max_cpu_time_sec": self.resource_limits.max_cpu_time_sec,
110
+ "max_wall_time_sec": self.resource_limits.max_wall_time_sec,
111
+ "max_file_size_mb": self.resource_limits.max_file_size_mb,
112
+ "max_open_files": self.resource_limits.max_open_files,
113
+ "max_processes": self.resource_limits.max_processes,
114
+ "network_enabled": self.resource_limits.network_enabled,
115
+ "filesystem_read": self.resource_limits.filesystem_read,
116
+ "filesystem_write": self.resource_limits.filesystem_write,
117
+ },
118
+ "require_signature": self.require_signature,
119
+ "min_signatures": self.min_signatures,
120
+ "allowed_signers": self.allowed_signers,
121
+ "blocked_modules": self.blocked_modules,
122
+ "allowed_permissions": self.allowed_permissions,
123
+ }
124
+
125
+ @classmethod
126
+ def from_dict(cls, data: dict[str, Any]) -> "SecurityPolicy":
127
+ """Create from dictionary."""
128
+ limits_data = data.get("resource_limits", {})
129
+ return cls(
130
+ name=data["name"],
131
+ description=data.get("description", ""),
132
+ isolation_level=IsolationLevel(data.get("isolation_level", "process")),
133
+ resource_limits=ResourceLimits(
134
+ max_memory_mb=limits_data.get("max_memory_mb", 256),
135
+ max_cpu_time_sec=limits_data.get("max_cpu_time_sec", 30),
136
+ max_wall_time_sec=limits_data.get("max_wall_time_sec", 60),
137
+ max_file_size_mb=limits_data.get("max_file_size_mb", 10),
138
+ max_open_files=limits_data.get("max_open_files", 10),
139
+ max_processes=limits_data.get("max_processes", 1),
140
+ network_enabled=limits_data.get("network_enabled", False),
141
+ filesystem_read=limits_data.get("filesystem_read", False),
142
+ filesystem_write=limits_data.get("filesystem_write", False),
143
+ ),
144
+ require_signature=data.get("require_signature", False),
145
+ min_signatures=data.get("min_signatures", 0),
146
+ allowed_signers=data.get("allowed_signers", []),
147
+ blocked_modules=data.get("blocked_modules", []),
148
+ allowed_permissions=data.get("allowed_permissions", []),
149
+ )
150
+
151
+
152
+ @dataclass
153
+ class SignatureInfo:
154
+ """Information about a plugin signature.
155
+
156
+ Attributes:
157
+ algorithm: Signature algorithm used.
158
+ signature: The signature value (hex or base64).
159
+ signer_id: ID of the signer.
160
+ timestamp: When the signature was created.
161
+ certificate: Optional certificate chain.
162
+ metadata: Additional metadata.
163
+ """
164
+
165
+ algorithm: SignatureAlgorithm
166
+ signature: str
167
+ signer_id: str
168
+ timestamp: datetime = field(default_factory=datetime.utcnow)
169
+ certificate: str | None = None
170
+ metadata: dict[str, Any] = field(default_factory=dict)
171
+
172
+ def to_dict(self) -> dict[str, Any]:
173
+ """Convert to dictionary."""
174
+ return {
175
+ "algorithm": self.algorithm.value,
176
+ "signature": self.signature,
177
+ "signer_id": self.signer_id,
178
+ "timestamp": self.timestamp.isoformat(),
179
+ "certificate": self.certificate,
180
+ "metadata": self.metadata,
181
+ }
182
+
183
+ @classmethod
184
+ def from_dict(cls, data: dict[str, Any]) -> "SignatureInfo":
185
+ """Create from dictionary."""
186
+ return cls(
187
+ algorithm=SignatureAlgorithm(data["algorithm"]),
188
+ signature=data["signature"],
189
+ signer_id=data["signer_id"],
190
+ timestamp=datetime.fromisoformat(data["timestamp"]),
191
+ certificate=data.get("certificate"),
192
+ metadata=data.get("metadata", {}),
193
+ )
194
+
195
+
196
+ @dataclass
197
+ class VerificationResult:
198
+ """Result of signature verification.
199
+
200
+ Attributes:
201
+ is_valid: Whether verification succeeded.
202
+ trust_level: Determined trust level.
203
+ signer_id: ID of the verified signer.
204
+ algorithm: Algorithm used.
205
+ errors: List of error messages.
206
+ warnings: List of warning messages.
207
+ verified_at: When verification was performed.
208
+ metadata: Additional verification metadata.
209
+ """
210
+
211
+ is_valid: bool
212
+ trust_level: TrustLevel = TrustLevel.UNVERIFIED
213
+ signer_id: str | None = None
214
+ algorithm: SignatureAlgorithm | None = None
215
+ errors: list[str] = field(default_factory=list)
216
+ warnings: list[str] = field(default_factory=list)
217
+ verified_at: datetime = field(default_factory=datetime.utcnow)
218
+ metadata: dict[str, Any] = field(default_factory=dict)
219
+
220
+ def to_dict(self) -> dict[str, Any]:
221
+ """Convert to dictionary."""
222
+ return {
223
+ "is_valid": self.is_valid,
224
+ "trust_level": self.trust_level.value,
225
+ "signer_id": self.signer_id,
226
+ "algorithm": self.algorithm.value if self.algorithm else None,
227
+ "errors": self.errors,
228
+ "warnings": self.warnings,
229
+ "verified_at": self.verified_at.isoformat(),
230
+ "metadata": self.metadata,
231
+ }
232
+
233
+
234
+ class ISigningService(Protocol):
235
+ """Protocol for signing services."""
236
+
237
+ def sign(
238
+ self,
239
+ data: bytes,
240
+ private_key: bytes,
241
+ signer_id: str,
242
+ ) -> SignatureInfo:
243
+ """Sign data and return signature info."""
244
+ ...
245
+
246
+ def verify(
247
+ self,
248
+ data: bytes,
249
+ signature_info: SignatureInfo,
250
+ public_key: bytes | None = None,
251
+ ) -> VerificationResult:
252
+ """Verify a signature."""
253
+ ...
254
+
255
+
256
+ class ITrustStore(Protocol):
257
+ """Protocol for trust stores."""
258
+
259
+ def add_signer(
260
+ self,
261
+ signer_id: str,
262
+ public_key: bytes,
263
+ trust_level: TrustLevel,
264
+ metadata: dict[str, Any] | None = None,
265
+ ) -> None:
266
+ """Add a trusted signer."""
267
+ ...
268
+
269
+ def remove_signer(self, signer_id: str) -> None:
270
+ """Remove a signer."""
271
+ ...
272
+
273
+ def get_trust_level(self, signer_id: str) -> TrustLevel | None:
274
+ """Get trust level for a signer."""
275
+ ...
276
+
277
+ def get_public_key(self, signer_id: str) -> bytes | None:
278
+ """Get public key for a signer."""
279
+ ...
280
+
281
+ def is_trusted(self, signer_id: str) -> bool:
282
+ """Check if signer is trusted."""
283
+ ...
284
+
285
+
286
+ class IVerificationChain(Protocol):
287
+ """Protocol for verification chains."""
288
+
289
+ def verify(
290
+ self,
291
+ data: bytes,
292
+ signatures: list[SignatureInfo],
293
+ context: dict[str, Any] | None = None,
294
+ ) -> VerificationResult:
295
+ """Verify signatures using the chain."""
296
+ ...