truthound-dashboard 1.4.4__py3-none-any.whl → 1.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. truthound_dashboard/api/alerts.py +75 -86
  2. truthound_dashboard/api/anomaly.py +7 -13
  3. truthound_dashboard/api/cross_alerts.py +38 -52
  4. truthound_dashboard/api/drift.py +49 -59
  5. truthound_dashboard/api/drift_monitor.py +234 -79
  6. truthound_dashboard/api/enterprise_sampling.py +498 -0
  7. truthound_dashboard/api/history.py +57 -5
  8. truthound_dashboard/api/lineage.py +3 -48
  9. truthound_dashboard/api/maintenance.py +104 -49
  10. truthound_dashboard/api/mask.py +1 -2
  11. truthound_dashboard/api/middleware.py +2 -1
  12. truthound_dashboard/api/model_monitoring.py +435 -311
  13. truthound_dashboard/api/notifications.py +227 -191
  14. truthound_dashboard/api/notifications_advanced.py +21 -20
  15. truthound_dashboard/api/observability.py +586 -0
  16. truthound_dashboard/api/plugins.py +2 -433
  17. truthound_dashboard/api/profile.py +199 -37
  18. truthound_dashboard/api/quality_reporter.py +701 -0
  19. truthound_dashboard/api/reports.py +7 -16
  20. truthound_dashboard/api/router.py +66 -0
  21. truthound_dashboard/api/rule_suggestions.py +5 -5
  22. truthound_dashboard/api/scan.py +17 -19
  23. truthound_dashboard/api/schedules.py +85 -50
  24. truthound_dashboard/api/schema_evolution.py +6 -6
  25. truthound_dashboard/api/schema_watcher.py +667 -0
  26. truthound_dashboard/api/sources.py +98 -27
  27. truthound_dashboard/api/tiering.py +1323 -0
  28. truthound_dashboard/api/triggers.py +14 -11
  29. truthound_dashboard/api/validations.py +12 -11
  30. truthound_dashboard/api/versioning.py +1 -6
  31. truthound_dashboard/core/__init__.py +129 -3
  32. truthound_dashboard/core/actions/__init__.py +62 -0
  33. truthound_dashboard/core/actions/custom.py +426 -0
  34. truthound_dashboard/core/actions/notifications.py +910 -0
  35. truthound_dashboard/core/actions/storage.py +472 -0
  36. truthound_dashboard/core/actions/webhook.py +281 -0
  37. truthound_dashboard/core/anomaly.py +262 -67
  38. truthound_dashboard/core/anomaly_explainer.py +4 -3
  39. truthound_dashboard/core/backends/__init__.py +67 -0
  40. truthound_dashboard/core/backends/base.py +299 -0
  41. truthound_dashboard/core/backends/errors.py +191 -0
  42. truthound_dashboard/core/backends/factory.py +423 -0
  43. truthound_dashboard/core/backends/mock_backend.py +451 -0
  44. truthound_dashboard/core/backends/truthound_backend.py +718 -0
  45. truthound_dashboard/core/checkpoint/__init__.py +87 -0
  46. truthound_dashboard/core/checkpoint/adapters.py +814 -0
  47. truthound_dashboard/core/checkpoint/checkpoint.py +491 -0
  48. truthound_dashboard/core/checkpoint/runner.py +270 -0
  49. truthound_dashboard/core/connections.py +437 -10
  50. truthound_dashboard/core/converters/__init__.py +14 -0
  51. truthound_dashboard/core/converters/truthound.py +620 -0
  52. truthound_dashboard/core/cross_alerts.py +540 -320
  53. truthound_dashboard/core/datasource_factory.py +1672 -0
  54. truthound_dashboard/core/drift_monitor.py +216 -20
  55. truthound_dashboard/core/enterprise_sampling.py +1291 -0
  56. truthound_dashboard/core/interfaces/__init__.py +225 -0
  57. truthound_dashboard/core/interfaces/actions.py +652 -0
  58. truthound_dashboard/core/interfaces/base.py +247 -0
  59. truthound_dashboard/core/interfaces/checkpoint.py +676 -0
  60. truthound_dashboard/core/interfaces/protocols.py +664 -0
  61. truthound_dashboard/core/interfaces/reporters.py +650 -0
  62. truthound_dashboard/core/interfaces/routing.py +646 -0
  63. truthound_dashboard/core/interfaces/triggers.py +619 -0
  64. truthound_dashboard/core/lineage.py +407 -71
  65. truthound_dashboard/core/model_monitoring.py +431 -3
  66. truthound_dashboard/core/notifications/base.py +4 -0
  67. truthound_dashboard/core/notifications/channels.py +501 -1203
  68. truthound_dashboard/core/notifications/deduplication/__init__.py +81 -115
  69. truthound_dashboard/core/notifications/deduplication/service.py +131 -348
  70. truthound_dashboard/core/notifications/dispatcher.py +202 -11
  71. truthound_dashboard/core/notifications/escalation/__init__.py +119 -106
  72. truthound_dashboard/core/notifications/escalation/engine.py +168 -358
  73. truthound_dashboard/core/notifications/routing/__init__.py +88 -128
  74. truthound_dashboard/core/notifications/routing/engine.py +90 -317
  75. truthound_dashboard/core/notifications/stats_aggregator.py +246 -1
  76. truthound_dashboard/core/notifications/throttling/__init__.py +67 -50
  77. truthound_dashboard/core/notifications/throttling/builder.py +117 -255
  78. truthound_dashboard/core/notifications/truthound_adapter.py +842 -0
  79. truthound_dashboard/core/phase5/collaboration.py +1 -1
  80. truthound_dashboard/core/plugins/lifecycle/__init__.py +0 -13
  81. truthound_dashboard/core/quality_reporter.py +1359 -0
  82. truthound_dashboard/core/report_history.py +0 -6
  83. truthound_dashboard/core/reporters/__init__.py +175 -14
  84. truthound_dashboard/core/reporters/adapters.py +943 -0
  85. truthound_dashboard/core/reporters/base.py +0 -3
  86. truthound_dashboard/core/reporters/builtin/__init__.py +18 -0
  87. truthound_dashboard/core/reporters/builtin/csv_reporter.py +111 -0
  88. truthound_dashboard/core/reporters/builtin/html_reporter.py +270 -0
  89. truthound_dashboard/core/reporters/builtin/json_reporter.py +127 -0
  90. truthound_dashboard/core/reporters/compat.py +266 -0
  91. truthound_dashboard/core/reporters/csv_reporter.py +2 -35
  92. truthound_dashboard/core/reporters/factory.py +526 -0
  93. truthound_dashboard/core/reporters/interfaces.py +745 -0
  94. truthound_dashboard/core/reporters/registry.py +1 -10
  95. truthound_dashboard/core/scheduler.py +165 -0
  96. truthound_dashboard/core/schema_evolution.py +3 -3
  97. truthound_dashboard/core/schema_watcher.py +1528 -0
  98. truthound_dashboard/core/services.py +595 -76
  99. truthound_dashboard/core/store_manager.py +810 -0
  100. truthound_dashboard/core/streaming_anomaly.py +169 -4
  101. truthound_dashboard/core/tiering.py +1309 -0
  102. truthound_dashboard/core/triggers/evaluators.py +178 -8
  103. truthound_dashboard/core/truthound_adapter.py +2620 -197
  104. truthound_dashboard/core/unified_alerts.py +23 -20
  105. truthound_dashboard/db/__init__.py +8 -0
  106. truthound_dashboard/db/database.py +8 -2
  107. truthound_dashboard/db/models.py +944 -25
  108. truthound_dashboard/db/repository.py +2 -0
  109. truthound_dashboard/main.py +11 -0
  110. truthound_dashboard/schemas/__init__.py +177 -16
  111. truthound_dashboard/schemas/base.py +44 -23
  112. truthound_dashboard/schemas/collaboration.py +19 -6
  113. truthound_dashboard/schemas/cross_alerts.py +19 -3
  114. truthound_dashboard/schemas/drift.py +61 -55
  115. truthound_dashboard/schemas/drift_monitor.py +67 -23
  116. truthound_dashboard/schemas/enterprise_sampling.py +653 -0
  117. truthound_dashboard/schemas/lineage.py +0 -33
  118. truthound_dashboard/schemas/mask.py +10 -8
  119. truthound_dashboard/schemas/model_monitoring.py +89 -10
  120. truthound_dashboard/schemas/notifications_advanced.py +13 -0
  121. truthound_dashboard/schemas/observability.py +453 -0
  122. truthound_dashboard/schemas/plugins.py +0 -280
  123. truthound_dashboard/schemas/profile.py +154 -247
  124. truthound_dashboard/schemas/quality_reporter.py +403 -0
  125. truthound_dashboard/schemas/reports.py +2 -2
  126. truthound_dashboard/schemas/rule_suggestion.py +8 -1
  127. truthound_dashboard/schemas/scan.py +4 -24
  128. truthound_dashboard/schemas/schedule.py +11 -3
  129. truthound_dashboard/schemas/schema_watcher.py +727 -0
  130. truthound_dashboard/schemas/source.py +17 -2
  131. truthound_dashboard/schemas/tiering.py +822 -0
  132. truthound_dashboard/schemas/triggers.py +16 -0
  133. truthound_dashboard/schemas/unified_alerts.py +7 -0
  134. truthound_dashboard/schemas/validation.py +0 -13
  135. truthound_dashboard/schemas/validators/base.py +41 -21
  136. truthound_dashboard/schemas/validators/business_rule_validators.py +244 -0
  137. truthound_dashboard/schemas/validators/localization_validators.py +273 -0
  138. truthound_dashboard/schemas/validators/ml_feature_validators.py +308 -0
  139. truthound_dashboard/schemas/validators/profiling_validators.py +275 -0
  140. truthound_dashboard/schemas/validators/referential_validators.py +312 -0
  141. truthound_dashboard/schemas/validators/registry.py +93 -8
  142. truthound_dashboard/schemas/validators/timeseries_validators.py +389 -0
  143. truthound_dashboard/schemas/versioning.py +1 -6
  144. truthound_dashboard/static/index.html +2 -2
  145. truthound_dashboard-1.5.0.dist-info/METADATA +309 -0
  146. {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.dist-info}/RECORD +149 -148
  147. truthound_dashboard/core/plugins/hooks/__init__.py +0 -63
  148. truthound_dashboard/core/plugins/hooks/decorators.py +0 -367
  149. truthound_dashboard/core/plugins/hooks/manager.py +0 -403
  150. truthound_dashboard/core/plugins/hooks/protocols.py +0 -265
  151. truthound_dashboard/core/plugins/lifecycle/hot_reload.py +0 -584
  152. truthound_dashboard/core/reporters/junit_reporter.py +0 -233
  153. truthound_dashboard/core/reporters/markdown_reporter.py +0 -207
  154. truthound_dashboard/core/reporters/pdf_reporter.py +0 -209
  155. truthound_dashboard/static/assets/_baseUniq-BcrSP13d.js +0 -1
  156. truthound_dashboard/static/assets/arc-DlYjKwIL.js +0 -1
  157. truthound_dashboard/static/assets/architectureDiagram-VXUJARFQ-Bb2drbQM.js +0 -36
  158. truthound_dashboard/static/assets/blockDiagram-VD42YOAC-BlsPG1CH.js +0 -122
  159. truthound_dashboard/static/assets/c4Diagram-YG6GDRKO-B9JdUoaC.js +0 -10
  160. truthound_dashboard/static/assets/channel-Q6mHF1Hd.js +0 -1
  161. truthound_dashboard/static/assets/chunk-4BX2VUAB-DmyoPVuJ.js +0 -1
  162. truthound_dashboard/static/assets/chunk-55IACEB6-Bcz6Siv8.js +0 -1
  163. truthound_dashboard/static/assets/chunk-B4BG7PRW-Br3G5Rum.js +0 -165
  164. truthound_dashboard/static/assets/chunk-DI55MBZ5-DuM9c23u.js +0 -220
  165. truthound_dashboard/static/assets/chunk-FMBD7UC4-DNU-5mvT.js +0 -15
  166. truthound_dashboard/static/assets/chunk-QN33PNHL-Im2yNcmS.js +0 -1
  167. truthound_dashboard/static/assets/chunk-QZHKN3VN-kZr8XFm1.js +0 -1
  168. truthound_dashboard/static/assets/chunk-TZMSLE5B-Q__360q_.js +0 -1
  169. truthound_dashboard/static/assets/classDiagram-2ON5EDUG-vtixxUyK.js +0 -1
  170. truthound_dashboard/static/assets/classDiagram-v2-WZHVMYZB-vtixxUyK.js +0 -1
  171. truthound_dashboard/static/assets/clone-BOt2LwD0.js +0 -1
  172. truthound_dashboard/static/assets/cose-bilkent-S5V4N54A-CBDw6iac.js +0 -1
  173. truthound_dashboard/static/assets/dagre-6UL2VRFP-XdKqmmY9.js +0 -4
  174. truthound_dashboard/static/assets/diagram-PSM6KHXK-DAZ8nx9V.js +0 -24
  175. truthound_dashboard/static/assets/diagram-QEK2KX5R-BRvDTbGD.js +0 -43
  176. truthound_dashboard/static/assets/diagram-S2PKOQOG-bQcczUkl.js +0 -24
  177. truthound_dashboard/static/assets/erDiagram-Q2GNP2WA-DPje7VMN.js +0 -60
  178. truthound_dashboard/static/assets/flowDiagram-NV44I4VS-B7BVtFVS.js +0 -162
  179. truthound_dashboard/static/assets/ganttDiagram-JELNMOA3-D6WKSS7U.js +0 -267
  180. truthound_dashboard/static/assets/gitGraphDiagram-NY62KEGX-D3vtVd3y.js +0 -65
  181. truthound_dashboard/static/assets/graph-BKgNKZVp.js +0 -1
  182. truthound_dashboard/static/assets/index-C6JSrkHo.css +0 -1
  183. truthound_dashboard/static/assets/index-DkU82VsU.js +0 -1800
  184. truthound_dashboard/static/assets/infoDiagram-WHAUD3N6-DnNCT429.js +0 -2
  185. truthound_dashboard/static/assets/journeyDiagram-XKPGCS4Q-DGiMozqS.js +0 -139
  186. truthound_dashboard/static/assets/kanban-definition-3W4ZIXB7-BV2gUgli.js +0 -89
  187. truthound_dashboard/static/assets/katex-Cu_Erd72.js +0 -261
  188. truthound_dashboard/static/assets/layout-DI2MfQ5G.js +0 -1
  189. truthound_dashboard/static/assets/min-DYdgXVcT.js +0 -1
  190. truthound_dashboard/static/assets/mindmap-definition-VGOIOE7T-C7x4ruxz.js +0 -68
  191. truthound_dashboard/static/assets/pieDiagram-ADFJNKIX-CAJaAB9f.js +0 -30
  192. truthound_dashboard/static/assets/quadrantDiagram-AYHSOK5B-DeqwDI46.js +0 -7
  193. truthound_dashboard/static/assets/requirementDiagram-UZGBJVZJ-e3XDpZIM.js +0 -64
  194. truthound_dashboard/static/assets/sankeyDiagram-TZEHDZUN-CNnAv5Ux.js +0 -10
  195. truthound_dashboard/static/assets/sequenceDiagram-WL72ISMW-Dsne-Of3.js +0 -145
  196. truthound_dashboard/static/assets/stateDiagram-FKZM4ZOC-Ee0sQXyb.js +0 -1
  197. truthound_dashboard/static/assets/stateDiagram-v2-4FDKWEC3-B26KqW_W.js +0 -1
  198. truthound_dashboard/static/assets/timeline-definition-IT6M3QCI-DZYi2yl3.js +0 -61
  199. truthound_dashboard/static/assets/treemap-KMMF4GRG-CY3f8In2.js +0 -128
  200. truthound_dashboard/static/assets/unmerged_dictionaries-Dd7xcPWG.js +0 -1
  201. truthound_dashboard/static/assets/xychartDiagram-PRI3JC2R-CS7fydZZ.js +0 -7
  202. truthound_dashboard-1.4.4.dist-info/METADATA +0 -507
  203. {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.dist-info}/WHEEL +0 -0
  204. {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.dist-info}/entry_points.txt +0 -0
  205. {truthound_dashboard-1.4.4.dist-info → truthound_dashboard-1.5.0.dist-info}/licenses/LICENSE +0 -0
@@ -27,9 +27,8 @@ from truthound_dashboard.core.plugins.validator_executor import ValidatorContext
27
27
  from truthound_dashboard.db.models import PluginStatus as DBPluginStatus
28
28
  from truthound_dashboard.db.models import PluginType as DBPluginType
29
29
  from truthound_dashboard.db.models import Validation
30
+ from truthound_dashboard.schemas.base import MessageResponse
30
31
  from truthound_dashboard.schemas.plugins import (
31
- AddSignerRequest,
32
- CodeAnalysisResult,
33
32
  CustomReporterCreate,
34
33
  CustomReporterListResponse,
35
34
  CustomReporterResponse,
@@ -43,13 +42,6 @@ from truthound_dashboard.schemas.plugins import (
43
42
  DependencyResolutionResponse,
44
43
  DocumentationRenderRequest,
45
44
  DocumentationRenderResponse,
46
- ExtendedSecurityReport,
47
- HookListResponse,
48
- HookRegistration,
49
- HookType,
50
- HotReloadConfigRequest,
51
- HotReloadResult,
52
- HotReloadStatus,
53
45
  MarketplaceSearchRequest,
54
46
  MarketplaceStats,
55
47
  PluginCreate,
@@ -69,17 +61,10 @@ from truthound_dashboard.schemas.plugins import (
69
61
  PluginUninstallResponse,
70
62
  PluginUpdate,
71
63
  PluginUpdateCheckResponse,
72
- RegisterHookRequest,
73
64
  ReporterGenerateRequest,
74
65
  ReporterGenerateResponse,
75
- SecurityAnalysisRequest,
76
- SecurityPolicyConfig,
77
- TrustStoreResponse,
78
- TrustedSigner,
79
66
  ValidatorTestRequest,
80
67
  ValidatorTestResponse,
81
- VerifySignatureRequest,
82
- VerifySignatureResponse,
83
68
  )
84
69
 
85
70
  from .deps import get_session
@@ -1212,7 +1197,7 @@ async def download_custom_report(
1212
1197
  session: SessionDep,
1213
1198
  reporter_id: str,
1214
1199
  validation_id: str = Query(..., description="Validation ID to generate report from"),
1215
- output_format: str = Query("html", description="Output format (html, json, csv, markdown, pdf)"),
1200
+ output_format: str = Query("html", description="Output format (html, json, csv)"),
1216
1201
  config: str | None = Query(None, description="JSON-encoded reporter configuration"),
1217
1202
  ) -> Any:
1218
1203
  """Download a report generated by a custom reporter.
@@ -1337,10 +1322,7 @@ def _get_extension(format_type: str) -> str:
1337
1322
  "html": "html",
1338
1323
  "json": "json",
1339
1324
  "csv": "csv",
1340
- "markdown": "md",
1341
- "pdf": "pdf",
1342
1325
  "xml": "xml",
1343
- "junit": "xml",
1344
1326
  }
1345
1327
  return extensions.get(format_type.lower(), "txt")
1346
1328
 
@@ -1454,115 +1436,6 @@ async def transition_plugin_state(
1454
1436
  )
1455
1437
 
1456
1438
 
1457
- # =============================================================================
1458
- # Plugin Hot Reload Endpoints
1459
- # =============================================================================
1460
-
1461
-
1462
- @router.get("/plugins/{plugin_id}/hot-reload", response_model=HotReloadStatus)
1463
- async def get_hot_reload_status(
1464
- session: SessionDep,
1465
- plugin_id: str,
1466
- ) -> HotReloadStatus:
1467
- """Get hot reload status for a plugin.
1468
-
1469
- Args:
1470
- session: Database session.
1471
- plugin_id: Plugin ID.
1472
-
1473
- Returns:
1474
- Hot reload status.
1475
- """
1476
- plugin = await plugin_registry.get_plugin(session, plugin_id=plugin_id)
1477
- if not plugin:
1478
- raise HTTPException(
1479
- status_code=status.HTTP_404_NOT_FOUND,
1480
- detail=f"Plugin {plugin_id} not found",
1481
- )
1482
-
1483
- # Return default status (would be managed by HotReloadManager in production)
1484
- from truthound_dashboard.schemas.plugins import ReloadStrategy
1485
-
1486
- return HotReloadStatus(
1487
- plugin_id=plugin_id,
1488
- enabled=False,
1489
- watching=False,
1490
- strategy=ReloadStrategy.MANUAL,
1491
- has_pending_reload=False,
1492
- )
1493
-
1494
-
1495
- @router.post("/plugins/{plugin_id}/hot-reload/configure", response_model=HotReloadStatus)
1496
- async def configure_hot_reload(
1497
- session: SessionDep,
1498
- plugin_id: str,
1499
- request: HotReloadConfigRequest,
1500
- ) -> HotReloadStatus:
1501
- """Configure hot reload for a plugin.
1502
-
1503
- Args:
1504
- session: Database session.
1505
- plugin_id: Plugin ID.
1506
- request: Hot reload configuration.
1507
-
1508
- Returns:
1509
- Updated hot reload status.
1510
- """
1511
- plugin = await plugin_registry.get_plugin(session, plugin_id=plugin_id)
1512
- if not plugin:
1513
- raise HTTPException(
1514
- status_code=status.HTTP_404_NOT_FOUND,
1515
- detail=f"Plugin {plugin_id} not found",
1516
- )
1517
-
1518
- # In production, this would configure the HotReloadManager
1519
- return HotReloadStatus(
1520
- plugin_id=plugin_id,
1521
- enabled=request.enabled,
1522
- watching=request.enabled,
1523
- strategy=request.strategy,
1524
- has_pending_reload=False,
1525
- )
1526
-
1527
-
1528
- @router.post("/plugins/{plugin_id}/hot-reload/trigger", response_model=HotReloadResult)
1529
- async def trigger_hot_reload(
1530
- session: SessionDep,
1531
- plugin_id: str,
1532
- ) -> HotReloadResult:
1533
- """Manually trigger a hot reload for a plugin.
1534
-
1535
- Args:
1536
- session: Database session.
1537
- plugin_id: Plugin ID.
1538
-
1539
- Returns:
1540
- Hot reload result.
1541
- """
1542
- plugin = await plugin_registry.get_plugin(session, plugin_id=plugin_id)
1543
- if not plugin:
1544
- raise HTTPException(
1545
- status_code=status.HTTP_404_NOT_FOUND,
1546
- detail=f"Plugin {plugin_id} not found",
1547
- )
1548
-
1549
- # In production, this would trigger the HotReloadManager
1550
- import time
1551
-
1552
- start = time.perf_counter()
1553
- # Simulate reload
1554
- duration = (time.perf_counter() - start) * 1000
1555
-
1556
- return HotReloadResult(
1557
- success=True,
1558
- plugin_id=plugin_id,
1559
- old_version=plugin.version,
1560
- new_version=plugin.version,
1561
- duration_ms=duration,
1562
- changes=[],
1563
- )
1564
-
1565
-
1566
1439
  # =============================================================================
1567
1440
  # Plugin Dependency Endpoints
1568
1441
  # =============================================================================
@@ -1691,310 +1564,6 @@ async def resolve_dependencies(
1691
1564
  )
1692
1565
 
1693
1566
 
1694
- # =============================================================================
1695
- # Plugin Security Endpoints
1696
- # =============================================================================
1697
-
1698
-
1699
- @router.get("/plugins/security/trust-store", response_model=TrustStoreResponse)
1700
- async def get_trust_store(session: SessionDep) -> TrustStoreResponse:
1701
- """Get the trust store containing trusted signers.
1702
-
1703
- Args:
1704
- session: Database session.
1705
-
1706
- Returns:
1707
- Trust store information.
1708
- """
1709
- # In production, this would read from the actual TrustStore
1710
- return TrustStoreResponse(
1711
- signers=[],
1712
- total_signers=0,
1713
- )
1714
-
1715
-
1716
- @router.post("/plugins/security/trust-store/signers", response_model=TrustedSigner)
1717
- async def add_trusted_signer(
1718
- session: SessionDep,
1719
- request: AddSignerRequest,
1720
- ) -> TrustedSigner:
1721
- """Add a trusted signer to the trust store.
1722
-
1723
- Args:
1724
- session: Database session.
1725
- request: Signer information.
1726
-
1727
- Returns:
1728
- Added signer.
1729
- """
1730
- from datetime import datetime
1731
-
1732
- from truthound_dashboard.schemas.plugins import SecurityLevel
1733
-
1734
- # In production, this would add to the actual TrustStore
1735
- return TrustedSigner(
1736
- signer_id=request.signer_id,
1737
- name=request.name,
1738
- public_key=request.public_key,
1739
- algorithm=request.algorithm,
1740
- added_at=datetime.utcnow(),
1741
- expires_at=request.expires_at,
1742
- is_active=True,
1743
- trust_level=request.trust_level or SecurityLevel.VERIFIED,
1744
- )
1745
-
1746
-
1747
- @router.delete("/plugins/security/trust-store/signers/{signer_id}")
1748
- async def remove_trusted_signer(
1749
- session: SessionDep,
1750
- signer_id: str,
1751
- ) -> dict[str, bool]:
1752
- """Remove a trusted signer from the trust store.
1753
-
1754
- Args:
1755
- session: Database session.
1756
- signer_id: Signer ID to remove.
1757
-
1758
- Returns:
1759
- Success status.
1760
- """
1761
- # In production, this would remove from the actual TrustStore
1762
- return {"success": True}
1763
-
1764
-
1765
- @router.get("/plugins/security/policy", response_model=SecurityPolicyConfig)
1766
- async def get_security_policy(session: SessionDep) -> SecurityPolicyConfig:
1767
- """Get current security policy configuration.
1768
-
1769
- Args:
1770
- session: Database session.
1771
-
1772
- Returns:
1773
- Security policy configuration.
1774
- """
1775
- from truthound_dashboard.schemas.plugins import (
1776
- IsolationLevel,
1777
- SecurityPolicyPreset,
1778
- )
1779
-
1780
- # Return default policy
1781
- return SecurityPolicyConfig(
1782
- preset=SecurityPolicyPreset.STANDARD,
1783
- isolation_level=IsolationLevel.PROCESS,
1784
- require_signature=True,
1785
- min_signatures=1,
1786
- memory_limit_mb=256,
1787
- cpu_time_limit_sec=30,
1788
- network_enabled=False,
1789
- filesystem_read=False,
1790
- filesystem_write=False,
1791
- )
1792
-
1793
-
1794
- @router.put("/plugins/security/policy", response_model=SecurityPolicyConfig)
1795
- async def update_security_policy(
1796
- session: SessionDep,
1797
- request: SecurityPolicyConfig,
1798
- ) -> SecurityPolicyConfig:
1799
- """Update security policy configuration.
1800
-
1801
- Args:
1802
- session: Database session.
1803
- request: New policy configuration.
1804
-
1805
- Returns:
1806
- Updated policy configuration.
1807
- """
1808
- # In production, this would persist the policy
1809
- return request
1810
-
1811
-
1812
- @router.post("/plugins/{plugin_id}/security/analyze", response_model=ExtendedSecurityReport)
1813
- async def analyze_plugin_security(
1814
- session: SessionDep,
1815
- plugin_id: str,
1816
- request: SecurityAnalysisRequest | None = None,
1817
- ) -> ExtendedSecurityReport:
1818
- """Perform detailed security analysis on a plugin.
1819
-
1820
- Args:
1821
- session: Database session.
1822
- plugin_id: Plugin ID.
1823
- request: Analysis request.
1824
-
1825
- Returns:
1826
- Extended security report.
1827
- """
1828
- from datetime import datetime
1829
-
1830
- from truthound_dashboard.schemas.plugins import SecurityLevel
1831
-
1832
- plugin = await plugin_registry.get_plugin(session, plugin_id=plugin_id)
1833
- if not plugin:
1834
- raise HTTPException(
1835
- status_code=status.HTTP_404_NOT_FOUND,
1836
- detail=f"Plugin {plugin_id} not found",
1837
- )
1838
-
1839
- # Perform security analysis
1840
- code = request.code if request else None
1841
- code_analysis = None
1842
-
1843
- if code:
1844
- code_analysis = CodeAnalysisResult(
1845
- is_safe=True,
1846
- issues=[],
1847
- warnings=[],
1848
- blocked_constructs=[],
1849
- detected_imports=[],
1850
- detected_permissions=[],
1851
- complexity_score=0,
1852
- )
1853
-
1854
- return ExtendedSecurityReport(
1855
- plugin_id=plugin_id,
1856
- analyzed_at=datetime.utcnow(),
1857
- risk_level=plugin.security_level or SecurityLevel.UNVERIFIED,
1858
- issues=[],
1859
- warnings=[],
1860
- permissions_required=plugin.permissions or [],
1861
- signature_valid=False,
1862
- sandbox_compatible=True,
1863
- code_analysis=code_analysis,
1864
- signature_count=0,
1865
- trust_level=plugin.security_level or SecurityLevel.UNVERIFIED,
1866
- can_run_in_sandbox=True,
1867
- code_hash="",
1868
- recommendations=["Sign the plugin for production use"],
1869
- )
1870
-
1871
-
1872
- @router.post("/plugins/security/verify-signature", response_model=VerifySignatureResponse)
1873
- async def verify_plugin_signature(
1874
- session: SessionDep,
1875
- request: VerifySignatureRequest,
1876
- ) -> VerifySignatureResponse:
1877
- """Verify a plugin signature.
1878
-
1879
- Args:
1880
- session: Database session.
1881
- request: Verification request.
1882
-
1883
- Returns:
1884
- Verification result.
1885
- """
1886
- # In production, this would use the actual verification chain
1887
- return VerifySignatureResponse(
1888
- is_valid=False,
1889
- error="Signature verification not implemented",
1890
- )
1891
-
1892
-
1893
- # =============================================================================
1894
- # Plugin Hooks Endpoints
1895
- # =============================================================================
1896
-
1897
-
1898
- @router.get("/plugins/hooks", response_model=HookListResponse)
1899
- async def list_hooks(
1900
- session: SessionDep,
1901
- hook_type: HookType | None = None,
1902
- plugin_id: str | None = None,
1903
- ) -> HookListResponse:
1904
- """List registered hooks.
1905
-
1906
- Args:
1907
- session: Database session.
1908
- hook_type: Filter by hook type.
1909
- plugin_id: Filter by plugin ID.
1910
-
1911
- Returns:
1912
- List of registered hooks.
1913
- """
1914
- # In production, this would query the HookManager
1915
- return HookListResponse(
1916
- hooks=[],
1917
- total=0,
1918
- by_type={},
1919
- )
1920
-
1921
-
1922
- @router.post("/plugins/hooks", response_model=HookRegistration)
1923
- async def register_hook(
1924
- session: SessionDep,
1925
- request: RegisterHookRequest,
1926
- ) -> HookRegistration:
1927
- """Register a new hook.
1928
-
1929
- Args:
1930
- session: Database session.
1931
- request: Hook registration request.
1932
-
1933
- Returns:
1934
- Registered hook.
1935
- """
1936
- import uuid
1937
-
1938
- from truthound_dashboard.schemas.plugins import HookPriority
1939
-
1940
- # In production, this would register with the HookManager
1941
- return HookRegistration(
1942
- id=str(uuid.uuid4()),
1943
- hook_type=request.hook_type,
1944
- plugin_id=request.plugin_id,
1945
- function_name=request.function_name,
1946
- priority=request.priority or HookPriority.NORMAL,
1947
- is_async=False,
1948
- is_enabled=True,
1949
- description=request.description,
1950
- )
1951
-
1952
-
1953
- @router.delete("/plugins/hooks/{hook_id}")
1954
- async def unregister_hook(
1955
- session: SessionDep,
1956
- hook_id: str,
1957
- ) -> dict[str, bool]:
1958
- """Unregister a hook.
1959
-
1960
- Args:
1961
- session: Database session.
1962
- hook_id: Hook ID to unregister.
1963
-
1964
- Returns:
1965
- Success status.
1966
- """
1967
- # In production, this would unregister from the HookManager
1968
- return {"success": True}
1969
-
1970
-
1971
- @router.get("/plugins/hooks/types")
1972
- async def list_hook_types() -> list[dict[str, str]]:
1973
- """List available hook types.
1974
-
1975
- Returns:
1976
- List of hook types with descriptions.
1977
- """
1978
- return [
1979
- {"type": "before_validation", "description": "Runs before validation starts"},
1980
- {"type": "after_validation", "description": "Runs after validation completes"},
1981
- {"type": "on_issue_found", "description": "Runs when a validation issue is found"},
1982
- {"type": "before_profile", "description": "Runs before data profiling"},
1983
- {"type": "after_profile", "description": "Runs after data profiling"},
1984
- {"type": "before_compare", "description": "Runs before drift comparison"},
1985
- {"type": "after_compare", "description": "Runs after drift comparison"},
1986
- {"type": "on_plugin_load", "description": "Runs when a plugin is loaded"},
1987
- {"type": "on_plugin_unload", "description": "Runs when a plugin is unloaded"},
1988
- {"type": "on_plugin_error", "description": "Runs when a plugin error occurs"},
1989
- {"type": "before_notification", "description": "Runs before sending notifications"},
1990
- {"type": "after_notification", "description": "Runs after sending notifications"},
1991
- {"type": "on_schedule_run", "description": "Runs when a schedule executes"},
1992
- {"type": "on_data_source_connect", "description": "Runs when connecting to a data source"},
1993
- {"type": "on_schema_change", "description": "Runs when schema changes are detected"},
1994
- {"type": "custom", "description": "Custom hook type"},
1995
- ]
1996
-
1997
-
1998
1567
  # =============================================================================
1999
1568
  # Plugin Documentation Endpoints
2000
1569
  # =============================================================================