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,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