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.
- truthound_dashboard/api/alerts.py +258 -0
- truthound_dashboard/api/anomaly.py +1302 -0
- truthound_dashboard/api/cross_alerts.py +352 -0
- truthound_dashboard/api/deps.py +143 -0
- truthound_dashboard/api/drift_monitor.py +540 -0
- truthound_dashboard/api/lineage.py +1151 -0
- truthound_dashboard/api/maintenance.py +363 -0
- truthound_dashboard/api/middleware.py +373 -1
- truthound_dashboard/api/model_monitoring.py +805 -0
- truthound_dashboard/api/notifications_advanced.py +2452 -0
- truthound_dashboard/api/plugins.py +2096 -0
- truthound_dashboard/api/profile.py +211 -14
- truthound_dashboard/api/reports.py +853 -0
- truthound_dashboard/api/router.py +147 -0
- truthound_dashboard/api/rule_suggestions.py +310 -0
- truthound_dashboard/api/schema_evolution.py +231 -0
- truthound_dashboard/api/sources.py +47 -3
- truthound_dashboard/api/triggers.py +190 -0
- truthound_dashboard/api/validations.py +13 -0
- truthound_dashboard/api/validators.py +333 -4
- truthound_dashboard/api/versioning.py +309 -0
- truthound_dashboard/api/websocket.py +301 -0
- truthound_dashboard/core/__init__.py +27 -0
- truthound_dashboard/core/anomaly.py +1395 -0
- truthound_dashboard/core/anomaly_explainer.py +633 -0
- truthound_dashboard/core/cache.py +206 -0
- truthound_dashboard/core/cached_services.py +422 -0
- truthound_dashboard/core/charts.py +352 -0
- truthound_dashboard/core/connections.py +1069 -42
- truthound_dashboard/core/cross_alerts.py +837 -0
- truthound_dashboard/core/drift_monitor.py +1477 -0
- truthound_dashboard/core/drift_sampling.py +669 -0
- truthound_dashboard/core/i18n/__init__.py +42 -0
- truthound_dashboard/core/i18n/detector.py +173 -0
- truthound_dashboard/core/i18n/messages.py +564 -0
- truthound_dashboard/core/lineage.py +971 -0
- truthound_dashboard/core/maintenance.py +443 -5
- truthound_dashboard/core/model_monitoring.py +1043 -0
- truthound_dashboard/core/notifications/channels.py +1020 -1
- truthound_dashboard/core/notifications/deduplication/__init__.py +143 -0
- truthound_dashboard/core/notifications/deduplication/policies.py +274 -0
- truthound_dashboard/core/notifications/deduplication/service.py +400 -0
- truthound_dashboard/core/notifications/deduplication/stores.py +2365 -0
- truthound_dashboard/core/notifications/deduplication/strategies.py +422 -0
- truthound_dashboard/core/notifications/dispatcher.py +43 -0
- truthound_dashboard/core/notifications/escalation/__init__.py +149 -0
- truthound_dashboard/core/notifications/escalation/backends.py +1384 -0
- truthound_dashboard/core/notifications/escalation/engine.py +429 -0
- truthound_dashboard/core/notifications/escalation/models.py +336 -0
- truthound_dashboard/core/notifications/escalation/scheduler.py +1187 -0
- truthound_dashboard/core/notifications/escalation/state_machine.py +330 -0
- truthound_dashboard/core/notifications/escalation/stores.py +2896 -0
- truthound_dashboard/core/notifications/events.py +49 -0
- truthound_dashboard/core/notifications/metrics/__init__.py +115 -0
- truthound_dashboard/core/notifications/metrics/base.py +528 -0
- truthound_dashboard/core/notifications/metrics/collectors.py +583 -0
- truthound_dashboard/core/notifications/routing/__init__.py +169 -0
- truthound_dashboard/core/notifications/routing/combinators.py +184 -0
- truthound_dashboard/core/notifications/routing/config.py +375 -0
- truthound_dashboard/core/notifications/routing/config_parser.py +867 -0
- truthound_dashboard/core/notifications/routing/engine.py +382 -0
- truthound_dashboard/core/notifications/routing/expression_engine.py +1269 -0
- truthound_dashboard/core/notifications/routing/jinja2_engine.py +774 -0
- truthound_dashboard/core/notifications/routing/rules.py +625 -0
- truthound_dashboard/core/notifications/routing/validator.py +678 -0
- truthound_dashboard/core/notifications/service.py +2 -0
- truthound_dashboard/core/notifications/stats_aggregator.py +850 -0
- truthound_dashboard/core/notifications/throttling/__init__.py +83 -0
- truthound_dashboard/core/notifications/throttling/builder.py +311 -0
- truthound_dashboard/core/notifications/throttling/stores.py +1859 -0
- truthound_dashboard/core/notifications/throttling/throttlers.py +633 -0
- truthound_dashboard/core/openlineage.py +1028 -0
- truthound_dashboard/core/plugins/__init__.py +39 -0
- truthound_dashboard/core/plugins/docs/__init__.py +39 -0
- truthound_dashboard/core/plugins/docs/extractor.py +703 -0
- truthound_dashboard/core/plugins/docs/renderers.py +804 -0
- truthound_dashboard/core/plugins/hooks/__init__.py +63 -0
- truthound_dashboard/core/plugins/hooks/decorators.py +367 -0
- truthound_dashboard/core/plugins/hooks/manager.py +403 -0
- truthound_dashboard/core/plugins/hooks/protocols.py +265 -0
- truthound_dashboard/core/plugins/lifecycle/__init__.py +41 -0
- truthound_dashboard/core/plugins/lifecycle/hot_reload.py +584 -0
- truthound_dashboard/core/plugins/lifecycle/machine.py +419 -0
- truthound_dashboard/core/plugins/lifecycle/states.py +266 -0
- truthound_dashboard/core/plugins/loader.py +504 -0
- truthound_dashboard/core/plugins/registry.py +810 -0
- truthound_dashboard/core/plugins/reporter_executor.py +588 -0
- truthound_dashboard/core/plugins/sandbox/__init__.py +59 -0
- truthound_dashboard/core/plugins/sandbox/code_validator.py +243 -0
- truthound_dashboard/core/plugins/sandbox/engines.py +770 -0
- truthound_dashboard/core/plugins/sandbox/protocols.py +194 -0
- truthound_dashboard/core/plugins/sandbox.py +617 -0
- truthound_dashboard/core/plugins/security/__init__.py +68 -0
- truthound_dashboard/core/plugins/security/analyzer.py +535 -0
- truthound_dashboard/core/plugins/security/policies.py +311 -0
- truthound_dashboard/core/plugins/security/protocols.py +296 -0
- truthound_dashboard/core/plugins/security/signing.py +842 -0
- truthound_dashboard/core/plugins/security.py +446 -0
- truthound_dashboard/core/plugins/validator_executor.py +401 -0
- truthound_dashboard/core/plugins/versioning/__init__.py +51 -0
- truthound_dashboard/core/plugins/versioning/constraints.py +377 -0
- truthound_dashboard/core/plugins/versioning/dependencies.py +541 -0
- truthound_dashboard/core/plugins/versioning/semver.py +266 -0
- truthound_dashboard/core/profile_comparison.py +601 -0
- truthound_dashboard/core/report_history.py +570 -0
- truthound_dashboard/core/reporters/__init__.py +57 -0
- truthound_dashboard/core/reporters/base.py +296 -0
- truthound_dashboard/core/reporters/csv_reporter.py +155 -0
- truthound_dashboard/core/reporters/html_reporter.py +598 -0
- truthound_dashboard/core/reporters/i18n/__init__.py +65 -0
- truthound_dashboard/core/reporters/i18n/base.py +494 -0
- truthound_dashboard/core/reporters/i18n/catalogs.py +930 -0
- truthound_dashboard/core/reporters/json_reporter.py +160 -0
- truthound_dashboard/core/reporters/junit_reporter.py +233 -0
- truthound_dashboard/core/reporters/markdown_reporter.py +207 -0
- truthound_dashboard/core/reporters/pdf_reporter.py +209 -0
- truthound_dashboard/core/reporters/registry.py +272 -0
- truthound_dashboard/core/rule_generator.py +2088 -0
- truthound_dashboard/core/scheduler.py +822 -12
- truthound_dashboard/core/schema_evolution.py +858 -0
- truthound_dashboard/core/services.py +152 -9
- truthound_dashboard/core/statistics.py +718 -0
- truthound_dashboard/core/streaming_anomaly.py +883 -0
- truthound_dashboard/core/triggers/__init__.py +45 -0
- truthound_dashboard/core/triggers/base.py +226 -0
- truthound_dashboard/core/triggers/evaluators.py +609 -0
- truthound_dashboard/core/triggers/factory.py +363 -0
- truthound_dashboard/core/unified_alerts.py +870 -0
- truthound_dashboard/core/validation_limits.py +509 -0
- truthound_dashboard/core/versioning.py +709 -0
- truthound_dashboard/core/websocket/__init__.py +59 -0
- truthound_dashboard/core/websocket/manager.py +512 -0
- truthound_dashboard/core/websocket/messages.py +130 -0
- truthound_dashboard/db/__init__.py +30 -0
- truthound_dashboard/db/models.py +3375 -3
- truthound_dashboard/main.py +22 -0
- truthound_dashboard/schemas/__init__.py +396 -1
- truthound_dashboard/schemas/anomaly.py +1258 -0
- truthound_dashboard/schemas/base.py +4 -0
- truthound_dashboard/schemas/cross_alerts.py +334 -0
- truthound_dashboard/schemas/drift_monitor.py +890 -0
- truthound_dashboard/schemas/lineage.py +428 -0
- truthound_dashboard/schemas/maintenance.py +154 -0
- truthound_dashboard/schemas/model_monitoring.py +374 -0
- truthound_dashboard/schemas/notifications_advanced.py +1363 -0
- truthound_dashboard/schemas/openlineage.py +704 -0
- truthound_dashboard/schemas/plugins.py +1293 -0
- truthound_dashboard/schemas/profile.py +420 -34
- truthound_dashboard/schemas/profile_comparison.py +242 -0
- truthound_dashboard/schemas/reports.py +285 -0
- truthound_dashboard/schemas/rule_suggestion.py +434 -0
- truthound_dashboard/schemas/schema_evolution.py +164 -0
- truthound_dashboard/schemas/source.py +117 -2
- truthound_dashboard/schemas/triggers.py +511 -0
- truthound_dashboard/schemas/unified_alerts.py +223 -0
- truthound_dashboard/schemas/validation.py +25 -1
- truthound_dashboard/schemas/validators/__init__.py +11 -0
- truthound_dashboard/schemas/validators/base.py +151 -0
- truthound_dashboard/schemas/versioning.py +152 -0
- truthound_dashboard/static/index.html +2 -2
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/METADATA +142 -22
- truthound_dashboard-1.4.0.dist-info/RECORD +239 -0
- truthound_dashboard/static/assets/index-BZG20KuF.js +0 -586
- truthound_dashboard/static/assets/index-D_HyZ3pb.css +0 -1
- truthound_dashboard/static/assets/unmerged_dictionaries-CtpqQBm0.js +0 -1
- truthound_dashboard-1.3.1.dist-info/RECORD +0 -110
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/WHEEL +0 -0
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.dist-info}/entry_points.txt +0 -0
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.0.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
|
+
...
|