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.
- 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.1.dist-info}/METADATA +147 -23
- truthound_dashboard-1.4.1.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.1.dist-info}/WHEEL +0 -0
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.1.dist-info}/entry_points.txt +0 -0
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"""Code Validation and Restriction Utilities.
|
|
2
|
+
|
|
3
|
+
This module provides utilities for validating and restricting
|
|
4
|
+
code execution in the sandbox.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import ast
|
|
10
|
+
import sys
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from .protocols import SandboxSecurityError
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RestrictedImporter:
|
|
17
|
+
"""Custom importer that restricts module imports.
|
|
18
|
+
|
|
19
|
+
This importer blocks dangerous modules and only allows
|
|
20
|
+
a whitelist of safe modules.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
# Always safe modules for data processing
|
|
24
|
+
SAFE_MODULES = frozenset({
|
|
25
|
+
"math", "statistics", "decimal", "fractions",
|
|
26
|
+
"random", "re", "json", "datetime",
|
|
27
|
+
"collections", "itertools", "functools",
|
|
28
|
+
"operator", "string", "textwrap", "unicodedata",
|
|
29
|
+
"typing", "dataclasses", "enum", "copy",
|
|
30
|
+
"numbers", "hashlib", "hmac", "base64",
|
|
31
|
+
"binascii", "io", "csv", "abc",
|
|
32
|
+
"contextlib", "warnings",
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
blocked_modules: list[str] | None = None,
|
|
38
|
+
allowed_modules: list[str] | None = None,
|
|
39
|
+
) -> None:
|
|
40
|
+
"""Initialize the restricted importer.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
blocked_modules: List of blocked module names.
|
|
44
|
+
allowed_modules: List of additional allowed module names.
|
|
45
|
+
"""
|
|
46
|
+
self.blocked_modules = set(blocked_modules or [])
|
|
47
|
+
self.allowed_modules = set(allowed_modules or [])
|
|
48
|
+
self.allowed_modules.update(self.SAFE_MODULES)
|
|
49
|
+
|
|
50
|
+
def find_module(
|
|
51
|
+
self, name: str, path: list[str] | None = None
|
|
52
|
+
) -> "RestrictedImporter | None":
|
|
53
|
+
"""Check if module import should be blocked.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
name: Module name.
|
|
57
|
+
path: Module path.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Self if import should be checked, None otherwise.
|
|
61
|
+
"""
|
|
62
|
+
base_module = name.split(".")[0]
|
|
63
|
+
|
|
64
|
+
# Check if explicitly blocked
|
|
65
|
+
if base_module in self.blocked_modules:
|
|
66
|
+
return self
|
|
67
|
+
|
|
68
|
+
# Check if not in allowed list
|
|
69
|
+
if self.allowed_modules and base_module not in self.allowed_modules:
|
|
70
|
+
return self
|
|
71
|
+
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
def load_module(self, name: str) -> Any:
|
|
75
|
+
"""Block the module load.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
name: Module name.
|
|
79
|
+
|
|
80
|
+
Raises:
|
|
81
|
+
SandboxSecurityError: Always, since this is only called for blocked imports.
|
|
82
|
+
"""
|
|
83
|
+
raise SandboxSecurityError(
|
|
84
|
+
f"Import of module '{name}' is not allowed in sandbox"
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class CodeValidator:
|
|
89
|
+
"""Validates code before execution."""
|
|
90
|
+
|
|
91
|
+
# Dangerous function calls
|
|
92
|
+
BLOCKED_FUNCTIONS = frozenset({
|
|
93
|
+
"eval", "exec", "compile",
|
|
94
|
+
"open", "input",
|
|
95
|
+
"__import__",
|
|
96
|
+
"globals", "locals", "vars",
|
|
97
|
+
"getattr", "setattr", "delattr",
|
|
98
|
+
"breakpoint", "exit", "quit",
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
# Dangerous attribute accesses
|
|
102
|
+
BLOCKED_ATTRIBUTES = frozenset({
|
|
103
|
+
"__class__", "__bases__", "__subclasses__", "__mro__",
|
|
104
|
+
"__code__", "__globals__", "__builtins__",
|
|
105
|
+
"__dict__", "__closure__", "__func__",
|
|
106
|
+
"__self__", "__module__", "__qualname__",
|
|
107
|
+
"__annotations__", "__reduce__", "__reduce_ex__",
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
def __init__(self, blocked_modules: list[str] | None = None) -> None:
|
|
111
|
+
"""Initialize the validator.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
blocked_modules: Additional blocked modules.
|
|
115
|
+
"""
|
|
116
|
+
self.blocked_modules = set(blocked_modules or [])
|
|
117
|
+
self.issues: list[str] = []
|
|
118
|
+
self.warnings: list[str] = []
|
|
119
|
+
|
|
120
|
+
def validate(self, code: str) -> tuple[bool, list[str]]:
|
|
121
|
+
"""Validate code for security issues.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
code: Python source code.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
Tuple of (is_valid, list of issues).
|
|
128
|
+
"""
|
|
129
|
+
self.issues = []
|
|
130
|
+
self.warnings = []
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
tree = ast.parse(code)
|
|
134
|
+
except SyntaxError as e:
|
|
135
|
+
return False, [f"Syntax error: {e}"]
|
|
136
|
+
|
|
137
|
+
self._visit(tree)
|
|
138
|
+
return len(self.issues) == 0, self.issues
|
|
139
|
+
|
|
140
|
+
def _visit(self, node: ast.AST) -> None:
|
|
141
|
+
"""Visit AST node and check for issues."""
|
|
142
|
+
# Check function calls
|
|
143
|
+
if isinstance(node, ast.Call):
|
|
144
|
+
self._check_call(node)
|
|
145
|
+
|
|
146
|
+
# Check attribute access
|
|
147
|
+
elif isinstance(node, ast.Attribute):
|
|
148
|
+
self._check_attribute(node)
|
|
149
|
+
|
|
150
|
+
# Check imports
|
|
151
|
+
elif isinstance(node, ast.Import):
|
|
152
|
+
self._check_import(node)
|
|
153
|
+
|
|
154
|
+
elif isinstance(node, ast.ImportFrom):
|
|
155
|
+
self._check_import_from(node)
|
|
156
|
+
|
|
157
|
+
# Visit children
|
|
158
|
+
for child in ast.iter_child_nodes(node):
|
|
159
|
+
self._visit(child)
|
|
160
|
+
|
|
161
|
+
def _check_call(self, node: ast.Call) -> None:
|
|
162
|
+
"""Check function call for blocked functions."""
|
|
163
|
+
func_name = None
|
|
164
|
+
|
|
165
|
+
if isinstance(node.func, ast.Name):
|
|
166
|
+
func_name = node.func.id
|
|
167
|
+
elif isinstance(node.func, ast.Attribute):
|
|
168
|
+
func_name = node.func.attr
|
|
169
|
+
|
|
170
|
+
if func_name and func_name in self.BLOCKED_FUNCTIONS:
|
|
171
|
+
self.issues.append(f"Blocked function call: {func_name}")
|
|
172
|
+
|
|
173
|
+
def _check_attribute(self, node: ast.Attribute) -> None:
|
|
174
|
+
"""Check attribute access for blocked attributes."""
|
|
175
|
+
if node.attr in self.BLOCKED_ATTRIBUTES:
|
|
176
|
+
self.issues.append(f"Blocked attribute access: {node.attr}")
|
|
177
|
+
|
|
178
|
+
def _check_import(self, node: ast.Import) -> None:
|
|
179
|
+
"""Check import statement for blocked modules."""
|
|
180
|
+
for alias in node.names:
|
|
181
|
+
module = alias.name.split(".")[0]
|
|
182
|
+
if module in self.blocked_modules:
|
|
183
|
+
self.issues.append(f"Blocked module import: {module}")
|
|
184
|
+
|
|
185
|
+
def _check_import_from(self, node: ast.ImportFrom) -> None:
|
|
186
|
+
"""Check from import for blocked modules."""
|
|
187
|
+
if node.module:
|
|
188
|
+
module = node.module.split(".")[0]
|
|
189
|
+
if module in self.blocked_modules:
|
|
190
|
+
self.issues.append(f"Blocked module import: {module}")
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def create_safe_builtins(allowed_builtins: list[str] | None = None) -> dict[str, Any]:
|
|
194
|
+
"""Create a restricted builtins dictionary.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
allowed_builtins: List of allowed builtin names.
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
Dictionary of allowed builtins.
|
|
201
|
+
"""
|
|
202
|
+
import builtins
|
|
203
|
+
|
|
204
|
+
default_allowed = [
|
|
205
|
+
"abs", "all", "any", "ascii", "bin", "bool",
|
|
206
|
+
"bytearray", "bytes", "callable", "chr", "classmethod",
|
|
207
|
+
"complex", "dict", "divmod", "enumerate",
|
|
208
|
+
"filter", "float", "format", "frozenset",
|
|
209
|
+
"hasattr", "hash", "hex", "id", "int", "isinstance",
|
|
210
|
+
"issubclass", "iter", "len", "list", "map", "max",
|
|
211
|
+
"min", "next", "object", "oct", "ord", "pow",
|
|
212
|
+
"print", "property", "range", "repr", "reversed",
|
|
213
|
+
"round", "set", "slice", "sorted",
|
|
214
|
+
"staticmethod", "str", "sum", "super", "tuple",
|
|
215
|
+
"type", "zip",
|
|
216
|
+
]
|
|
217
|
+
|
|
218
|
+
allowed = allowed_builtins or default_allowed
|
|
219
|
+
safe_builtins: dict[str, Any] = {}
|
|
220
|
+
|
|
221
|
+
for name in allowed:
|
|
222
|
+
if hasattr(builtins, name):
|
|
223
|
+
safe_builtins[name] = getattr(builtins, name)
|
|
224
|
+
|
|
225
|
+
# Add essential values
|
|
226
|
+
safe_builtins["None"] = None
|
|
227
|
+
safe_builtins["True"] = True
|
|
228
|
+
safe_builtins["False"] = False
|
|
229
|
+
safe_builtins["__name__"] = "__sandbox__"
|
|
230
|
+
safe_builtins["__doc__"] = None
|
|
231
|
+
|
|
232
|
+
# Add safe exceptions
|
|
233
|
+
safe_exceptions = [
|
|
234
|
+
"Exception", "ValueError", "TypeError", "KeyError",
|
|
235
|
+
"IndexError", "AttributeError", "RuntimeError",
|
|
236
|
+
"StopIteration", "NotImplementedError", "ZeroDivisionError",
|
|
237
|
+
"AssertionError", "ImportError", "OverflowError",
|
|
238
|
+
]
|
|
239
|
+
for exc_name in safe_exceptions:
|
|
240
|
+
if hasattr(builtins, exc_name):
|
|
241
|
+
safe_builtins[exc_name] = getattr(builtins, exc_name)
|
|
242
|
+
|
|
243
|
+
return safe_builtins
|