truthound 1.0.8__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 (877) hide show
  1. truthound/__init__.py +162 -0
  2. truthound/adapters.py +100 -0
  3. truthound/api.py +365 -0
  4. truthound/audit/__init__.py +248 -0
  5. truthound/audit/core.py +967 -0
  6. truthound/audit/filters.py +620 -0
  7. truthound/audit/formatters.py +707 -0
  8. truthound/audit/logger.py +902 -0
  9. truthound/audit/middleware.py +571 -0
  10. truthound/audit/storage.py +1083 -0
  11. truthound/benchmark/__init__.py +123 -0
  12. truthound/benchmark/base.py +757 -0
  13. truthound/benchmark/comparison.py +635 -0
  14. truthound/benchmark/generators.py +706 -0
  15. truthound/benchmark/reporters.py +718 -0
  16. truthound/benchmark/runner.py +635 -0
  17. truthound/benchmark/scenarios.py +712 -0
  18. truthound/cache.py +252 -0
  19. truthound/checkpoint/__init__.py +136 -0
  20. truthound/checkpoint/actions/__init__.py +164 -0
  21. truthound/checkpoint/actions/base.py +324 -0
  22. truthound/checkpoint/actions/custom.py +234 -0
  23. truthound/checkpoint/actions/discord_notify.py +290 -0
  24. truthound/checkpoint/actions/email_notify.py +405 -0
  25. truthound/checkpoint/actions/github_action.py +406 -0
  26. truthound/checkpoint/actions/opsgenie.py +1499 -0
  27. truthound/checkpoint/actions/pagerduty.py +226 -0
  28. truthound/checkpoint/actions/slack_notify.py +233 -0
  29. truthound/checkpoint/actions/store_result.py +249 -0
  30. truthound/checkpoint/actions/teams_notify.py +1570 -0
  31. truthound/checkpoint/actions/telegram_notify.py +419 -0
  32. truthound/checkpoint/actions/update_docs.py +552 -0
  33. truthound/checkpoint/actions/webhook.py +293 -0
  34. truthound/checkpoint/analytics/__init__.py +147 -0
  35. truthound/checkpoint/analytics/aggregations/__init__.py +23 -0
  36. truthound/checkpoint/analytics/aggregations/rollup.py +481 -0
  37. truthound/checkpoint/analytics/aggregations/time_bucket.py +306 -0
  38. truthound/checkpoint/analytics/analyzers/__init__.py +17 -0
  39. truthound/checkpoint/analytics/analyzers/anomaly.py +386 -0
  40. truthound/checkpoint/analytics/analyzers/base.py +270 -0
  41. truthound/checkpoint/analytics/analyzers/forecast.py +421 -0
  42. truthound/checkpoint/analytics/analyzers/trend.py +314 -0
  43. truthound/checkpoint/analytics/models.py +292 -0
  44. truthound/checkpoint/analytics/protocols.py +549 -0
  45. truthound/checkpoint/analytics/service.py +718 -0
  46. truthound/checkpoint/analytics/stores/__init__.py +16 -0
  47. truthound/checkpoint/analytics/stores/base.py +306 -0
  48. truthound/checkpoint/analytics/stores/memory_store.py +353 -0
  49. truthound/checkpoint/analytics/stores/sqlite_store.py +557 -0
  50. truthound/checkpoint/analytics/stores/timescale_store.py +501 -0
  51. truthound/checkpoint/async_actions.py +794 -0
  52. truthound/checkpoint/async_base.py +708 -0
  53. truthound/checkpoint/async_checkpoint.py +617 -0
  54. truthound/checkpoint/async_runner.py +639 -0
  55. truthound/checkpoint/checkpoint.py +527 -0
  56. truthound/checkpoint/ci/__init__.py +61 -0
  57. truthound/checkpoint/ci/detector.py +355 -0
  58. truthound/checkpoint/ci/reporter.py +436 -0
  59. truthound/checkpoint/ci/templates.py +454 -0
  60. truthound/checkpoint/circuitbreaker/__init__.py +133 -0
  61. truthound/checkpoint/circuitbreaker/breaker.py +542 -0
  62. truthound/checkpoint/circuitbreaker/core.py +252 -0
  63. truthound/checkpoint/circuitbreaker/detection.py +459 -0
  64. truthound/checkpoint/circuitbreaker/middleware.py +389 -0
  65. truthound/checkpoint/circuitbreaker/registry.py +357 -0
  66. truthound/checkpoint/distributed/__init__.py +139 -0
  67. truthound/checkpoint/distributed/backends/__init__.py +35 -0
  68. truthound/checkpoint/distributed/backends/celery_backend.py +503 -0
  69. truthound/checkpoint/distributed/backends/kubernetes_backend.py +696 -0
  70. truthound/checkpoint/distributed/backends/local_backend.py +397 -0
  71. truthound/checkpoint/distributed/backends/ray_backend.py +625 -0
  72. truthound/checkpoint/distributed/base.py +774 -0
  73. truthound/checkpoint/distributed/orchestrator.py +765 -0
  74. truthound/checkpoint/distributed/protocols.py +842 -0
  75. truthound/checkpoint/distributed/registry.py +449 -0
  76. truthound/checkpoint/idempotency/__init__.py +120 -0
  77. truthound/checkpoint/idempotency/core.py +295 -0
  78. truthound/checkpoint/idempotency/fingerprint.py +454 -0
  79. truthound/checkpoint/idempotency/locking.py +604 -0
  80. truthound/checkpoint/idempotency/service.py +592 -0
  81. truthound/checkpoint/idempotency/stores.py +653 -0
  82. truthound/checkpoint/monitoring/__init__.py +134 -0
  83. truthound/checkpoint/monitoring/aggregators/__init__.py +15 -0
  84. truthound/checkpoint/monitoring/aggregators/base.py +372 -0
  85. truthound/checkpoint/monitoring/aggregators/realtime.py +300 -0
  86. truthound/checkpoint/monitoring/aggregators/window.py +493 -0
  87. truthound/checkpoint/monitoring/collectors/__init__.py +17 -0
  88. truthound/checkpoint/monitoring/collectors/base.py +257 -0
  89. truthound/checkpoint/monitoring/collectors/memory_collector.py +617 -0
  90. truthound/checkpoint/monitoring/collectors/prometheus_collector.py +451 -0
  91. truthound/checkpoint/monitoring/collectors/redis_collector.py +518 -0
  92. truthound/checkpoint/monitoring/events.py +410 -0
  93. truthound/checkpoint/monitoring/protocols.py +636 -0
  94. truthound/checkpoint/monitoring/service.py +578 -0
  95. truthound/checkpoint/monitoring/views/__init__.py +17 -0
  96. truthound/checkpoint/monitoring/views/base.py +172 -0
  97. truthound/checkpoint/monitoring/views/queue_view.py +220 -0
  98. truthound/checkpoint/monitoring/views/task_view.py +240 -0
  99. truthound/checkpoint/monitoring/views/worker_view.py +263 -0
  100. truthound/checkpoint/registry.py +337 -0
  101. truthound/checkpoint/runner.py +356 -0
  102. truthound/checkpoint/transaction/__init__.py +133 -0
  103. truthound/checkpoint/transaction/base.py +389 -0
  104. truthound/checkpoint/transaction/compensatable.py +537 -0
  105. truthound/checkpoint/transaction/coordinator.py +576 -0
  106. truthound/checkpoint/transaction/executor.py +622 -0
  107. truthound/checkpoint/transaction/idempotency.py +534 -0
  108. truthound/checkpoint/transaction/saga/__init__.py +143 -0
  109. truthound/checkpoint/transaction/saga/builder.py +584 -0
  110. truthound/checkpoint/transaction/saga/definition.py +515 -0
  111. truthound/checkpoint/transaction/saga/event_store.py +542 -0
  112. truthound/checkpoint/transaction/saga/patterns.py +833 -0
  113. truthound/checkpoint/transaction/saga/runner.py +718 -0
  114. truthound/checkpoint/transaction/saga/state_machine.py +793 -0
  115. truthound/checkpoint/transaction/saga/strategies.py +780 -0
  116. truthound/checkpoint/transaction/saga/testing.py +886 -0
  117. truthound/checkpoint/triggers/__init__.py +58 -0
  118. truthound/checkpoint/triggers/base.py +237 -0
  119. truthound/checkpoint/triggers/event.py +385 -0
  120. truthound/checkpoint/triggers/schedule.py +355 -0
  121. truthound/cli.py +2358 -0
  122. truthound/cli_modules/__init__.py +124 -0
  123. truthound/cli_modules/advanced/__init__.py +45 -0
  124. truthound/cli_modules/advanced/benchmark.py +343 -0
  125. truthound/cli_modules/advanced/docs.py +225 -0
  126. truthound/cli_modules/advanced/lineage.py +209 -0
  127. truthound/cli_modules/advanced/ml.py +320 -0
  128. truthound/cli_modules/advanced/realtime.py +196 -0
  129. truthound/cli_modules/checkpoint/__init__.py +46 -0
  130. truthound/cli_modules/checkpoint/init.py +114 -0
  131. truthound/cli_modules/checkpoint/list.py +71 -0
  132. truthound/cli_modules/checkpoint/run.py +159 -0
  133. truthound/cli_modules/checkpoint/validate.py +67 -0
  134. truthound/cli_modules/common/__init__.py +71 -0
  135. truthound/cli_modules/common/errors.py +414 -0
  136. truthound/cli_modules/common/options.py +419 -0
  137. truthound/cli_modules/common/output.py +507 -0
  138. truthound/cli_modules/common/protocol.py +552 -0
  139. truthound/cli_modules/core/__init__.py +48 -0
  140. truthound/cli_modules/core/check.py +123 -0
  141. truthound/cli_modules/core/compare.py +104 -0
  142. truthound/cli_modules/core/learn.py +57 -0
  143. truthound/cli_modules/core/mask.py +77 -0
  144. truthound/cli_modules/core/profile.py +65 -0
  145. truthound/cli_modules/core/scan.py +61 -0
  146. truthound/cli_modules/profiler/__init__.py +51 -0
  147. truthound/cli_modules/profiler/auto_profile.py +175 -0
  148. truthound/cli_modules/profiler/metadata.py +107 -0
  149. truthound/cli_modules/profiler/suite.py +283 -0
  150. truthound/cli_modules/registry.py +431 -0
  151. truthound/cli_modules/scaffolding/__init__.py +89 -0
  152. truthound/cli_modules/scaffolding/base.py +631 -0
  153. truthound/cli_modules/scaffolding/commands.py +545 -0
  154. truthound/cli_modules/scaffolding/plugins.py +1072 -0
  155. truthound/cli_modules/scaffolding/reporters.py +594 -0
  156. truthound/cli_modules/scaffolding/validators.py +1127 -0
  157. truthound/common/__init__.py +18 -0
  158. truthound/common/resilience/__init__.py +130 -0
  159. truthound/common/resilience/bulkhead.py +266 -0
  160. truthound/common/resilience/circuit_breaker.py +516 -0
  161. truthound/common/resilience/composite.py +332 -0
  162. truthound/common/resilience/config.py +292 -0
  163. truthound/common/resilience/protocols.py +217 -0
  164. truthound/common/resilience/rate_limiter.py +404 -0
  165. truthound/common/resilience/retry.py +341 -0
  166. truthound/datadocs/__init__.py +260 -0
  167. truthound/datadocs/base.py +571 -0
  168. truthound/datadocs/builder.py +761 -0
  169. truthound/datadocs/charts.py +764 -0
  170. truthound/datadocs/dashboard/__init__.py +63 -0
  171. truthound/datadocs/dashboard/app.py +576 -0
  172. truthound/datadocs/dashboard/components.py +584 -0
  173. truthound/datadocs/dashboard/state.py +240 -0
  174. truthound/datadocs/engine/__init__.py +46 -0
  175. truthound/datadocs/engine/context.py +376 -0
  176. truthound/datadocs/engine/pipeline.py +618 -0
  177. truthound/datadocs/engine/registry.py +469 -0
  178. truthound/datadocs/exporters/__init__.py +49 -0
  179. truthound/datadocs/exporters/base.py +198 -0
  180. truthound/datadocs/exporters/html.py +178 -0
  181. truthound/datadocs/exporters/json_exporter.py +253 -0
  182. truthound/datadocs/exporters/markdown.py +284 -0
  183. truthound/datadocs/exporters/pdf.py +392 -0
  184. truthound/datadocs/i18n/__init__.py +86 -0
  185. truthound/datadocs/i18n/catalog.py +960 -0
  186. truthound/datadocs/i18n/formatting.py +505 -0
  187. truthound/datadocs/i18n/loader.py +256 -0
  188. truthound/datadocs/i18n/plurals.py +378 -0
  189. truthound/datadocs/renderers/__init__.py +42 -0
  190. truthound/datadocs/renderers/base.py +401 -0
  191. truthound/datadocs/renderers/custom.py +342 -0
  192. truthound/datadocs/renderers/jinja.py +697 -0
  193. truthound/datadocs/sections.py +736 -0
  194. truthound/datadocs/styles.py +931 -0
  195. truthound/datadocs/themes/__init__.py +101 -0
  196. truthound/datadocs/themes/base.py +336 -0
  197. truthound/datadocs/themes/default.py +417 -0
  198. truthound/datadocs/themes/enterprise.py +419 -0
  199. truthound/datadocs/themes/loader.py +336 -0
  200. truthound/datadocs/themes.py +301 -0
  201. truthound/datadocs/transformers/__init__.py +57 -0
  202. truthound/datadocs/transformers/base.py +268 -0
  203. truthound/datadocs/transformers/enrichers.py +544 -0
  204. truthound/datadocs/transformers/filters.py +447 -0
  205. truthound/datadocs/transformers/i18n.py +468 -0
  206. truthound/datadocs/versioning/__init__.py +62 -0
  207. truthound/datadocs/versioning/diff.py +639 -0
  208. truthound/datadocs/versioning/storage.py +497 -0
  209. truthound/datadocs/versioning/version.py +358 -0
  210. truthound/datasources/__init__.py +223 -0
  211. truthound/datasources/_async_protocols.py +222 -0
  212. truthound/datasources/_protocols.py +159 -0
  213. truthound/datasources/adapters.py +428 -0
  214. truthound/datasources/async_base.py +599 -0
  215. truthound/datasources/async_factory.py +511 -0
  216. truthound/datasources/base.py +516 -0
  217. truthound/datasources/factory.py +433 -0
  218. truthound/datasources/nosql/__init__.py +47 -0
  219. truthound/datasources/nosql/base.py +487 -0
  220. truthound/datasources/nosql/elasticsearch.py +801 -0
  221. truthound/datasources/nosql/mongodb.py +636 -0
  222. truthound/datasources/pandas_optimized.py +582 -0
  223. truthound/datasources/pandas_source.py +216 -0
  224. truthound/datasources/polars_source.py +395 -0
  225. truthound/datasources/spark_source.py +479 -0
  226. truthound/datasources/sql/__init__.py +154 -0
  227. truthound/datasources/sql/base.py +710 -0
  228. truthound/datasources/sql/bigquery.py +410 -0
  229. truthound/datasources/sql/cloud_base.py +199 -0
  230. truthound/datasources/sql/databricks.py +471 -0
  231. truthound/datasources/sql/mysql.py +316 -0
  232. truthound/datasources/sql/oracle.py +427 -0
  233. truthound/datasources/sql/postgresql.py +321 -0
  234. truthound/datasources/sql/redshift.py +479 -0
  235. truthound/datasources/sql/snowflake.py +439 -0
  236. truthound/datasources/sql/sqlite.py +286 -0
  237. truthound/datasources/sql/sqlserver.py +437 -0
  238. truthound/datasources/streaming/__init__.py +47 -0
  239. truthound/datasources/streaming/base.py +350 -0
  240. truthound/datasources/streaming/kafka.py +670 -0
  241. truthound/decorators.py +98 -0
  242. truthound/docs/__init__.py +69 -0
  243. truthound/docs/extractor.py +971 -0
  244. truthound/docs/generator.py +601 -0
  245. truthound/docs/parser.py +1037 -0
  246. truthound/docs/renderer.py +999 -0
  247. truthound/drift/__init__.py +22 -0
  248. truthound/drift/compare.py +189 -0
  249. truthound/drift/detectors.py +464 -0
  250. truthound/drift/report.py +160 -0
  251. truthound/execution/__init__.py +65 -0
  252. truthound/execution/_protocols.py +324 -0
  253. truthound/execution/base.py +576 -0
  254. truthound/execution/distributed/__init__.py +179 -0
  255. truthound/execution/distributed/aggregations.py +731 -0
  256. truthound/execution/distributed/arrow_bridge.py +817 -0
  257. truthound/execution/distributed/base.py +550 -0
  258. truthound/execution/distributed/dask_engine.py +976 -0
  259. truthound/execution/distributed/mixins.py +766 -0
  260. truthound/execution/distributed/protocols.py +756 -0
  261. truthound/execution/distributed/ray_engine.py +1127 -0
  262. truthound/execution/distributed/registry.py +446 -0
  263. truthound/execution/distributed/spark_engine.py +1011 -0
  264. truthound/execution/distributed/validator_adapter.py +682 -0
  265. truthound/execution/pandas_engine.py +401 -0
  266. truthound/execution/polars_engine.py +497 -0
  267. truthound/execution/pushdown/__init__.py +230 -0
  268. truthound/execution/pushdown/ast.py +1550 -0
  269. truthound/execution/pushdown/builder.py +1550 -0
  270. truthound/execution/pushdown/dialects.py +1072 -0
  271. truthound/execution/pushdown/executor.py +829 -0
  272. truthound/execution/pushdown/optimizer.py +1041 -0
  273. truthound/execution/sql_engine.py +518 -0
  274. truthound/infrastructure/__init__.py +189 -0
  275. truthound/infrastructure/audit.py +1515 -0
  276. truthound/infrastructure/config.py +1133 -0
  277. truthound/infrastructure/encryption.py +1132 -0
  278. truthound/infrastructure/logging.py +1503 -0
  279. truthound/infrastructure/metrics.py +1220 -0
  280. truthound/lineage/__init__.py +89 -0
  281. truthound/lineage/base.py +746 -0
  282. truthound/lineage/impact_analysis.py +474 -0
  283. truthound/lineage/integrations/__init__.py +22 -0
  284. truthound/lineage/integrations/openlineage.py +548 -0
  285. truthound/lineage/tracker.py +512 -0
  286. truthound/lineage/visualization/__init__.py +33 -0
  287. truthound/lineage/visualization/protocols.py +145 -0
  288. truthound/lineage/visualization/renderers/__init__.py +20 -0
  289. truthound/lineage/visualization/renderers/cytoscape.py +329 -0
  290. truthound/lineage/visualization/renderers/d3.py +331 -0
  291. truthound/lineage/visualization/renderers/graphviz.py +276 -0
  292. truthound/lineage/visualization/renderers/mermaid.py +308 -0
  293. truthound/maskers.py +113 -0
  294. truthound/ml/__init__.py +124 -0
  295. truthound/ml/anomaly_models/__init__.py +31 -0
  296. truthound/ml/anomaly_models/ensemble.py +362 -0
  297. truthound/ml/anomaly_models/isolation_forest.py +444 -0
  298. truthound/ml/anomaly_models/statistical.py +392 -0
  299. truthound/ml/base.py +1178 -0
  300. truthound/ml/drift_detection/__init__.py +26 -0
  301. truthound/ml/drift_detection/concept.py +381 -0
  302. truthound/ml/drift_detection/distribution.py +361 -0
  303. truthound/ml/drift_detection/feature.py +442 -0
  304. truthound/ml/drift_detection/multivariate.py +495 -0
  305. truthound/ml/monitoring/__init__.py +88 -0
  306. truthound/ml/monitoring/alerting/__init__.py +33 -0
  307. truthound/ml/monitoring/alerting/handlers.py +427 -0
  308. truthound/ml/monitoring/alerting/rules.py +508 -0
  309. truthound/ml/monitoring/collectors/__init__.py +19 -0
  310. truthound/ml/monitoring/collectors/composite.py +105 -0
  311. truthound/ml/monitoring/collectors/drift.py +324 -0
  312. truthound/ml/monitoring/collectors/performance.py +179 -0
  313. truthound/ml/monitoring/collectors/quality.py +369 -0
  314. truthound/ml/monitoring/monitor.py +536 -0
  315. truthound/ml/monitoring/protocols.py +451 -0
  316. truthound/ml/monitoring/stores/__init__.py +15 -0
  317. truthound/ml/monitoring/stores/memory.py +201 -0
  318. truthound/ml/monitoring/stores/prometheus.py +296 -0
  319. truthound/ml/rule_learning/__init__.py +25 -0
  320. truthound/ml/rule_learning/constraint_miner.py +443 -0
  321. truthound/ml/rule_learning/pattern_learner.py +499 -0
  322. truthound/ml/rule_learning/profile_learner.py +462 -0
  323. truthound/multitenancy/__init__.py +326 -0
  324. truthound/multitenancy/core.py +852 -0
  325. truthound/multitenancy/integration.py +597 -0
  326. truthound/multitenancy/isolation.py +630 -0
  327. truthound/multitenancy/manager.py +770 -0
  328. truthound/multitenancy/middleware.py +765 -0
  329. truthound/multitenancy/quota.py +537 -0
  330. truthound/multitenancy/resolvers.py +603 -0
  331. truthound/multitenancy/storage.py +703 -0
  332. truthound/observability/__init__.py +307 -0
  333. truthound/observability/context.py +531 -0
  334. truthound/observability/instrumentation.py +611 -0
  335. truthound/observability/logging.py +887 -0
  336. truthound/observability/metrics.py +1157 -0
  337. truthound/observability/tracing/__init__.py +178 -0
  338. truthound/observability/tracing/baggage.py +310 -0
  339. truthound/observability/tracing/config.py +426 -0
  340. truthound/observability/tracing/exporter.py +787 -0
  341. truthound/observability/tracing/integration.py +1018 -0
  342. truthound/observability/tracing/otel/__init__.py +146 -0
  343. truthound/observability/tracing/otel/adapter.py +982 -0
  344. truthound/observability/tracing/otel/bridge.py +1177 -0
  345. truthound/observability/tracing/otel/compat.py +681 -0
  346. truthound/observability/tracing/otel/config.py +691 -0
  347. truthound/observability/tracing/otel/detection.py +327 -0
  348. truthound/observability/tracing/otel/protocols.py +426 -0
  349. truthound/observability/tracing/processor.py +561 -0
  350. truthound/observability/tracing/propagator.py +757 -0
  351. truthound/observability/tracing/provider.py +569 -0
  352. truthound/observability/tracing/resource.py +515 -0
  353. truthound/observability/tracing/sampler.py +487 -0
  354. truthound/observability/tracing/span.py +676 -0
  355. truthound/plugins/__init__.py +198 -0
  356. truthound/plugins/base.py +599 -0
  357. truthound/plugins/cli.py +680 -0
  358. truthound/plugins/dependencies/__init__.py +42 -0
  359. truthound/plugins/dependencies/graph.py +422 -0
  360. truthound/plugins/dependencies/resolver.py +417 -0
  361. truthound/plugins/discovery.py +379 -0
  362. truthound/plugins/docs/__init__.py +46 -0
  363. truthound/plugins/docs/extractor.py +444 -0
  364. truthound/plugins/docs/renderer.py +499 -0
  365. truthound/plugins/enterprise_manager.py +877 -0
  366. truthound/plugins/examples/__init__.py +19 -0
  367. truthound/plugins/examples/custom_validators.py +317 -0
  368. truthound/plugins/examples/slack_notifier.py +312 -0
  369. truthound/plugins/examples/xml_reporter.py +254 -0
  370. truthound/plugins/hooks.py +558 -0
  371. truthound/plugins/lifecycle/__init__.py +43 -0
  372. truthound/plugins/lifecycle/hot_reload.py +402 -0
  373. truthound/plugins/lifecycle/manager.py +371 -0
  374. truthound/plugins/manager.py +736 -0
  375. truthound/plugins/registry.py +338 -0
  376. truthound/plugins/security/__init__.py +93 -0
  377. truthound/plugins/security/exceptions.py +332 -0
  378. truthound/plugins/security/policies.py +348 -0
  379. truthound/plugins/security/protocols.py +643 -0
  380. truthound/plugins/security/sandbox/__init__.py +45 -0
  381. truthound/plugins/security/sandbox/context.py +158 -0
  382. truthound/plugins/security/sandbox/engines/__init__.py +19 -0
  383. truthound/plugins/security/sandbox/engines/container.py +379 -0
  384. truthound/plugins/security/sandbox/engines/noop.py +144 -0
  385. truthound/plugins/security/sandbox/engines/process.py +336 -0
  386. truthound/plugins/security/sandbox/factory.py +211 -0
  387. truthound/plugins/security/signing/__init__.py +57 -0
  388. truthound/plugins/security/signing/service.py +330 -0
  389. truthound/plugins/security/signing/trust_store.py +368 -0
  390. truthound/plugins/security/signing/verifier.py +459 -0
  391. truthound/plugins/versioning/__init__.py +41 -0
  392. truthound/plugins/versioning/constraints.py +297 -0
  393. truthound/plugins/versioning/resolver.py +329 -0
  394. truthound/profiler/__init__.py +1729 -0
  395. truthound/profiler/_lazy.py +452 -0
  396. truthound/profiler/ab_testing/__init__.py +80 -0
  397. truthound/profiler/ab_testing/analysis.py +449 -0
  398. truthound/profiler/ab_testing/base.py +257 -0
  399. truthound/profiler/ab_testing/experiment.py +395 -0
  400. truthound/profiler/ab_testing/tracking.py +368 -0
  401. truthound/profiler/auto_threshold.py +1170 -0
  402. truthound/profiler/base.py +579 -0
  403. truthound/profiler/cache_patterns.py +911 -0
  404. truthound/profiler/caching.py +1303 -0
  405. truthound/profiler/column_profiler.py +712 -0
  406. truthound/profiler/comparison.py +1007 -0
  407. truthound/profiler/custom_patterns.py +1170 -0
  408. truthound/profiler/dashboard/__init__.py +50 -0
  409. truthound/profiler/dashboard/app.py +476 -0
  410. truthound/profiler/dashboard/components.py +457 -0
  411. truthound/profiler/dashboard/config.py +72 -0
  412. truthound/profiler/distributed/__init__.py +83 -0
  413. truthound/profiler/distributed/base.py +281 -0
  414. truthound/profiler/distributed/dask_backend.py +498 -0
  415. truthound/profiler/distributed/local_backend.py +293 -0
  416. truthound/profiler/distributed/profiler.py +304 -0
  417. truthound/profiler/distributed/ray_backend.py +374 -0
  418. truthound/profiler/distributed/spark_backend.py +375 -0
  419. truthound/profiler/distributed.py +1366 -0
  420. truthound/profiler/enterprise_sampling.py +1065 -0
  421. truthound/profiler/errors.py +488 -0
  422. truthound/profiler/evolution/__init__.py +91 -0
  423. truthound/profiler/evolution/alerts.py +426 -0
  424. truthound/profiler/evolution/changes.py +206 -0
  425. truthound/profiler/evolution/compatibility.py +365 -0
  426. truthound/profiler/evolution/detector.py +372 -0
  427. truthound/profiler/evolution/protocols.py +121 -0
  428. truthound/profiler/generators/__init__.py +48 -0
  429. truthound/profiler/generators/base.py +384 -0
  430. truthound/profiler/generators/ml_rules.py +375 -0
  431. truthound/profiler/generators/pattern_rules.py +384 -0
  432. truthound/profiler/generators/schema_rules.py +267 -0
  433. truthound/profiler/generators/stats_rules.py +324 -0
  434. truthound/profiler/generators/suite_generator.py +857 -0
  435. truthound/profiler/i18n.py +1542 -0
  436. truthound/profiler/incremental.py +554 -0
  437. truthound/profiler/incremental_validation.py +1710 -0
  438. truthound/profiler/integration/__init__.py +73 -0
  439. truthound/profiler/integration/adapters.py +345 -0
  440. truthound/profiler/integration/context.py +371 -0
  441. truthound/profiler/integration/executor.py +527 -0
  442. truthound/profiler/integration/naming.py +75 -0
  443. truthound/profiler/integration/protocols.py +243 -0
  444. truthound/profiler/memory.py +1185 -0
  445. truthound/profiler/migration/__init__.py +60 -0
  446. truthound/profiler/migration/base.py +345 -0
  447. truthound/profiler/migration/manager.py +444 -0
  448. truthound/profiler/migration/v1_0_to_v1_1.py +484 -0
  449. truthound/profiler/ml/__init__.py +73 -0
  450. truthound/profiler/ml/base.py +244 -0
  451. truthound/profiler/ml/classifier.py +507 -0
  452. truthound/profiler/ml/feature_extraction.py +604 -0
  453. truthound/profiler/ml/pretrained.py +448 -0
  454. truthound/profiler/ml_inference.py +1276 -0
  455. truthound/profiler/native_patterns.py +815 -0
  456. truthound/profiler/observability.py +1184 -0
  457. truthound/profiler/process_timeout.py +1566 -0
  458. truthound/profiler/progress.py +568 -0
  459. truthound/profiler/progress_callbacks.py +1734 -0
  460. truthound/profiler/quality.py +1345 -0
  461. truthound/profiler/resilience.py +1180 -0
  462. truthound/profiler/sampled_matcher.py +794 -0
  463. truthound/profiler/sampling.py +1288 -0
  464. truthound/profiler/scheduling/__init__.py +82 -0
  465. truthound/profiler/scheduling/protocols.py +214 -0
  466. truthound/profiler/scheduling/scheduler.py +474 -0
  467. truthound/profiler/scheduling/storage.py +457 -0
  468. truthound/profiler/scheduling/triggers.py +449 -0
  469. truthound/profiler/schema.py +603 -0
  470. truthound/profiler/streaming.py +685 -0
  471. truthound/profiler/streaming_patterns.py +1354 -0
  472. truthound/profiler/suite_cli.py +625 -0
  473. truthound/profiler/suite_config.py +789 -0
  474. truthound/profiler/suite_export.py +1268 -0
  475. truthound/profiler/table_profiler.py +547 -0
  476. truthound/profiler/timeout.py +565 -0
  477. truthound/profiler/validation.py +1532 -0
  478. truthound/profiler/visualization/__init__.py +118 -0
  479. truthound/profiler/visualization/base.py +346 -0
  480. truthound/profiler/visualization/generator.py +1259 -0
  481. truthound/profiler/visualization/plotly_renderer.py +811 -0
  482. truthound/profiler/visualization/renderers.py +669 -0
  483. truthound/profiler/visualization/sections.py +540 -0
  484. truthound/profiler/visualization.py +2122 -0
  485. truthound/profiler/yaml_validation.py +1151 -0
  486. truthound/py.typed +0 -0
  487. truthound/ratelimit/__init__.py +248 -0
  488. truthound/ratelimit/algorithms.py +1108 -0
  489. truthound/ratelimit/core.py +573 -0
  490. truthound/ratelimit/integration.py +532 -0
  491. truthound/ratelimit/limiter.py +663 -0
  492. truthound/ratelimit/middleware.py +700 -0
  493. truthound/ratelimit/policy.py +792 -0
  494. truthound/ratelimit/storage.py +763 -0
  495. truthound/rbac/__init__.py +340 -0
  496. truthound/rbac/core.py +976 -0
  497. truthound/rbac/integration.py +760 -0
  498. truthound/rbac/manager.py +1052 -0
  499. truthound/rbac/middleware.py +842 -0
  500. truthound/rbac/policy.py +954 -0
  501. truthound/rbac/storage.py +878 -0
  502. truthound/realtime/__init__.py +141 -0
  503. truthound/realtime/adapters/__init__.py +43 -0
  504. truthound/realtime/adapters/base.py +533 -0
  505. truthound/realtime/adapters/kafka.py +487 -0
  506. truthound/realtime/adapters/kinesis.py +479 -0
  507. truthound/realtime/adapters/mock.py +243 -0
  508. truthound/realtime/base.py +553 -0
  509. truthound/realtime/factory.py +382 -0
  510. truthound/realtime/incremental.py +660 -0
  511. truthound/realtime/processing/__init__.py +67 -0
  512. truthound/realtime/processing/exactly_once.py +575 -0
  513. truthound/realtime/processing/state.py +547 -0
  514. truthound/realtime/processing/windows.py +647 -0
  515. truthound/realtime/protocols.py +569 -0
  516. truthound/realtime/streaming.py +605 -0
  517. truthound/realtime/testing/__init__.py +32 -0
  518. truthound/realtime/testing/containers.py +615 -0
  519. truthound/realtime/testing/fixtures.py +484 -0
  520. truthound/report.py +280 -0
  521. truthound/reporters/__init__.py +46 -0
  522. truthound/reporters/_protocols.py +30 -0
  523. truthound/reporters/base.py +324 -0
  524. truthound/reporters/ci/__init__.py +66 -0
  525. truthound/reporters/ci/azure.py +436 -0
  526. truthound/reporters/ci/base.py +509 -0
  527. truthound/reporters/ci/bitbucket.py +567 -0
  528. truthound/reporters/ci/circleci.py +547 -0
  529. truthound/reporters/ci/detection.py +364 -0
  530. truthound/reporters/ci/factory.py +182 -0
  531. truthound/reporters/ci/github.py +388 -0
  532. truthound/reporters/ci/gitlab.py +471 -0
  533. truthound/reporters/ci/jenkins.py +525 -0
  534. truthound/reporters/console_reporter.py +299 -0
  535. truthound/reporters/factory.py +211 -0
  536. truthound/reporters/html_reporter.py +524 -0
  537. truthound/reporters/json_reporter.py +256 -0
  538. truthound/reporters/markdown_reporter.py +280 -0
  539. truthound/reporters/sdk/__init__.py +174 -0
  540. truthound/reporters/sdk/builder.py +558 -0
  541. truthound/reporters/sdk/mixins.py +1150 -0
  542. truthound/reporters/sdk/schema.py +1493 -0
  543. truthound/reporters/sdk/templates.py +666 -0
  544. truthound/reporters/sdk/testing.py +968 -0
  545. truthound/scanners.py +170 -0
  546. truthound/scheduling/__init__.py +122 -0
  547. truthound/scheduling/cron.py +1136 -0
  548. truthound/scheduling/presets.py +212 -0
  549. truthound/schema.py +275 -0
  550. truthound/secrets/__init__.py +173 -0
  551. truthound/secrets/base.py +618 -0
  552. truthound/secrets/cloud.py +682 -0
  553. truthound/secrets/integration.py +507 -0
  554. truthound/secrets/manager.py +633 -0
  555. truthound/secrets/oidc/__init__.py +172 -0
  556. truthound/secrets/oidc/base.py +902 -0
  557. truthound/secrets/oidc/credential_provider.py +623 -0
  558. truthound/secrets/oidc/exchangers.py +1001 -0
  559. truthound/secrets/oidc/github/__init__.py +110 -0
  560. truthound/secrets/oidc/github/claims.py +718 -0
  561. truthound/secrets/oidc/github/enhanced_provider.py +693 -0
  562. truthound/secrets/oidc/github/trust_policy.py +742 -0
  563. truthound/secrets/oidc/github/verification.py +723 -0
  564. truthound/secrets/oidc/github/workflow.py +691 -0
  565. truthound/secrets/oidc/providers.py +825 -0
  566. truthound/secrets/providers.py +506 -0
  567. truthound/secrets/resolver.py +495 -0
  568. truthound/stores/__init__.py +177 -0
  569. truthound/stores/backends/__init__.py +18 -0
  570. truthound/stores/backends/_protocols.py +340 -0
  571. truthound/stores/backends/azure_blob.py +530 -0
  572. truthound/stores/backends/concurrent_filesystem.py +915 -0
  573. truthound/stores/backends/connection_pool.py +1365 -0
  574. truthound/stores/backends/database.py +743 -0
  575. truthound/stores/backends/filesystem.py +538 -0
  576. truthound/stores/backends/gcs.py +399 -0
  577. truthound/stores/backends/memory.py +354 -0
  578. truthound/stores/backends/s3.py +434 -0
  579. truthound/stores/backpressure/__init__.py +84 -0
  580. truthound/stores/backpressure/base.py +375 -0
  581. truthound/stores/backpressure/circuit_breaker.py +434 -0
  582. truthound/stores/backpressure/monitor.py +376 -0
  583. truthound/stores/backpressure/strategies.py +677 -0
  584. truthound/stores/base.py +551 -0
  585. truthound/stores/batching/__init__.py +65 -0
  586. truthound/stores/batching/base.py +305 -0
  587. truthound/stores/batching/buffer.py +370 -0
  588. truthound/stores/batching/store.py +248 -0
  589. truthound/stores/batching/writer.py +521 -0
  590. truthound/stores/caching/__init__.py +60 -0
  591. truthound/stores/caching/backends.py +684 -0
  592. truthound/stores/caching/base.py +356 -0
  593. truthound/stores/caching/store.py +305 -0
  594. truthound/stores/compression/__init__.py +193 -0
  595. truthound/stores/compression/adaptive.py +694 -0
  596. truthound/stores/compression/base.py +514 -0
  597. truthound/stores/compression/pipeline.py +868 -0
  598. truthound/stores/compression/providers.py +672 -0
  599. truthound/stores/compression/streaming.py +832 -0
  600. truthound/stores/concurrency/__init__.py +81 -0
  601. truthound/stores/concurrency/atomic.py +556 -0
  602. truthound/stores/concurrency/index.py +775 -0
  603. truthound/stores/concurrency/locks.py +576 -0
  604. truthound/stores/concurrency/manager.py +482 -0
  605. truthound/stores/encryption/__init__.py +297 -0
  606. truthound/stores/encryption/base.py +952 -0
  607. truthound/stores/encryption/keys.py +1191 -0
  608. truthound/stores/encryption/pipeline.py +903 -0
  609. truthound/stores/encryption/providers.py +953 -0
  610. truthound/stores/encryption/streaming.py +950 -0
  611. truthound/stores/expectations.py +227 -0
  612. truthound/stores/factory.py +246 -0
  613. truthound/stores/migration/__init__.py +75 -0
  614. truthound/stores/migration/base.py +480 -0
  615. truthound/stores/migration/manager.py +347 -0
  616. truthound/stores/migration/registry.py +382 -0
  617. truthound/stores/migration/store.py +559 -0
  618. truthound/stores/observability/__init__.py +106 -0
  619. truthound/stores/observability/audit.py +718 -0
  620. truthound/stores/observability/config.py +270 -0
  621. truthound/stores/observability/factory.py +208 -0
  622. truthound/stores/observability/metrics.py +636 -0
  623. truthound/stores/observability/protocols.py +410 -0
  624. truthound/stores/observability/store.py +570 -0
  625. truthound/stores/observability/tracing.py +784 -0
  626. truthound/stores/replication/__init__.py +76 -0
  627. truthound/stores/replication/base.py +260 -0
  628. truthound/stores/replication/monitor.py +269 -0
  629. truthound/stores/replication/store.py +439 -0
  630. truthound/stores/replication/syncer.py +391 -0
  631. truthound/stores/results.py +359 -0
  632. truthound/stores/retention/__init__.py +77 -0
  633. truthound/stores/retention/base.py +378 -0
  634. truthound/stores/retention/policies.py +621 -0
  635. truthound/stores/retention/scheduler.py +279 -0
  636. truthound/stores/retention/store.py +526 -0
  637. truthound/stores/streaming/__init__.py +138 -0
  638. truthound/stores/streaming/base.py +801 -0
  639. truthound/stores/streaming/database.py +984 -0
  640. truthound/stores/streaming/filesystem.py +719 -0
  641. truthound/stores/streaming/reader.py +629 -0
  642. truthound/stores/streaming/s3.py +843 -0
  643. truthound/stores/streaming/writer.py +790 -0
  644. truthound/stores/tiering/__init__.py +108 -0
  645. truthound/stores/tiering/base.py +462 -0
  646. truthound/stores/tiering/manager.py +249 -0
  647. truthound/stores/tiering/policies.py +692 -0
  648. truthound/stores/tiering/store.py +526 -0
  649. truthound/stores/versioning/__init__.py +56 -0
  650. truthound/stores/versioning/base.py +376 -0
  651. truthound/stores/versioning/store.py +660 -0
  652. truthound/stores/versioning/strategies.py +353 -0
  653. truthound/types.py +56 -0
  654. truthound/validators/__init__.py +774 -0
  655. truthound/validators/aggregate/__init__.py +27 -0
  656. truthound/validators/aggregate/central.py +116 -0
  657. truthound/validators/aggregate/extremes.py +116 -0
  658. truthound/validators/aggregate/spread.py +118 -0
  659. truthound/validators/aggregate/sum.py +64 -0
  660. truthound/validators/aggregate/type.py +78 -0
  661. truthound/validators/anomaly/__init__.py +93 -0
  662. truthound/validators/anomaly/base.py +431 -0
  663. truthound/validators/anomaly/ml_based.py +1190 -0
  664. truthound/validators/anomaly/multivariate.py +647 -0
  665. truthound/validators/anomaly/statistical.py +599 -0
  666. truthound/validators/base.py +1089 -0
  667. truthound/validators/business_rule/__init__.py +46 -0
  668. truthound/validators/business_rule/base.py +147 -0
  669. truthound/validators/business_rule/checksum.py +509 -0
  670. truthound/validators/business_rule/financial.py +526 -0
  671. truthound/validators/cache.py +733 -0
  672. truthound/validators/completeness/__init__.py +39 -0
  673. truthound/validators/completeness/conditional.py +73 -0
  674. truthound/validators/completeness/default.py +98 -0
  675. truthound/validators/completeness/empty.py +103 -0
  676. truthound/validators/completeness/nan.py +337 -0
  677. truthound/validators/completeness/null.py +152 -0
  678. truthound/validators/cross_table/__init__.py +17 -0
  679. truthound/validators/cross_table/aggregate.py +333 -0
  680. truthound/validators/cross_table/row_count.py +122 -0
  681. truthound/validators/datetime/__init__.py +29 -0
  682. truthound/validators/datetime/format.py +78 -0
  683. truthound/validators/datetime/freshness.py +269 -0
  684. truthound/validators/datetime/order.py +73 -0
  685. truthound/validators/datetime/parseable.py +185 -0
  686. truthound/validators/datetime/range.py +202 -0
  687. truthound/validators/datetime/timezone.py +69 -0
  688. truthound/validators/distribution/__init__.py +49 -0
  689. truthound/validators/distribution/distribution.py +128 -0
  690. truthound/validators/distribution/monotonic.py +119 -0
  691. truthound/validators/distribution/outlier.py +178 -0
  692. truthound/validators/distribution/quantile.py +80 -0
  693. truthound/validators/distribution/range.py +254 -0
  694. truthound/validators/distribution/set.py +125 -0
  695. truthound/validators/distribution/statistical.py +459 -0
  696. truthound/validators/drift/__init__.py +79 -0
  697. truthound/validators/drift/base.py +427 -0
  698. truthound/validators/drift/multi_feature.py +401 -0
  699. truthound/validators/drift/numeric.py +395 -0
  700. truthound/validators/drift/psi.py +446 -0
  701. truthound/validators/drift/statistical.py +510 -0
  702. truthound/validators/enterprise.py +1658 -0
  703. truthound/validators/geospatial/__init__.py +80 -0
  704. truthound/validators/geospatial/base.py +97 -0
  705. truthound/validators/geospatial/boundary.py +238 -0
  706. truthound/validators/geospatial/coordinate.py +351 -0
  707. truthound/validators/geospatial/distance.py +399 -0
  708. truthound/validators/geospatial/polygon.py +665 -0
  709. truthound/validators/i18n/__init__.py +308 -0
  710. truthound/validators/i18n/bidi.py +571 -0
  711. truthound/validators/i18n/catalogs.py +570 -0
  712. truthound/validators/i18n/dialects.py +763 -0
  713. truthound/validators/i18n/extended_catalogs.py +549 -0
  714. truthound/validators/i18n/formatting.py +1434 -0
  715. truthound/validators/i18n/loader.py +1020 -0
  716. truthound/validators/i18n/messages.py +521 -0
  717. truthound/validators/i18n/plural.py +683 -0
  718. truthound/validators/i18n/protocols.py +855 -0
  719. truthound/validators/i18n/tms.py +1162 -0
  720. truthound/validators/localization/__init__.py +53 -0
  721. truthound/validators/localization/base.py +122 -0
  722. truthound/validators/localization/chinese.py +362 -0
  723. truthound/validators/localization/japanese.py +275 -0
  724. truthound/validators/localization/korean.py +524 -0
  725. truthound/validators/memory/__init__.py +94 -0
  726. truthound/validators/memory/approximate_knn.py +506 -0
  727. truthound/validators/memory/base.py +547 -0
  728. truthound/validators/memory/sgd_online.py +719 -0
  729. truthound/validators/memory/streaming_ecdf.py +753 -0
  730. truthound/validators/ml_feature/__init__.py +54 -0
  731. truthound/validators/ml_feature/base.py +249 -0
  732. truthound/validators/ml_feature/correlation.py +299 -0
  733. truthound/validators/ml_feature/leakage.py +344 -0
  734. truthound/validators/ml_feature/null_impact.py +270 -0
  735. truthound/validators/ml_feature/scale.py +264 -0
  736. truthound/validators/multi_column/__init__.py +89 -0
  737. truthound/validators/multi_column/arithmetic.py +284 -0
  738. truthound/validators/multi_column/base.py +231 -0
  739. truthound/validators/multi_column/comparison.py +273 -0
  740. truthound/validators/multi_column/consistency.py +312 -0
  741. truthound/validators/multi_column/statistical.py +299 -0
  742. truthound/validators/optimization/__init__.py +164 -0
  743. truthound/validators/optimization/aggregation.py +563 -0
  744. truthound/validators/optimization/covariance.py +556 -0
  745. truthound/validators/optimization/geo.py +626 -0
  746. truthound/validators/optimization/graph.py +587 -0
  747. truthound/validators/optimization/orchestrator.py +970 -0
  748. truthound/validators/optimization/profiling.py +1312 -0
  749. truthound/validators/privacy/__init__.py +223 -0
  750. truthound/validators/privacy/base.py +635 -0
  751. truthound/validators/privacy/ccpa.py +670 -0
  752. truthound/validators/privacy/gdpr.py +728 -0
  753. truthound/validators/privacy/global_patterns.py +604 -0
  754. truthound/validators/privacy/plugins.py +867 -0
  755. truthound/validators/profiling/__init__.py +52 -0
  756. truthound/validators/profiling/base.py +175 -0
  757. truthound/validators/profiling/cardinality.py +312 -0
  758. truthound/validators/profiling/entropy.py +391 -0
  759. truthound/validators/profiling/frequency.py +455 -0
  760. truthound/validators/pushdown_support.py +660 -0
  761. truthound/validators/query/__init__.py +91 -0
  762. truthound/validators/query/aggregate.py +346 -0
  763. truthound/validators/query/base.py +246 -0
  764. truthound/validators/query/column.py +249 -0
  765. truthound/validators/query/expression.py +274 -0
  766. truthound/validators/query/result.py +323 -0
  767. truthound/validators/query/row_count.py +264 -0
  768. truthound/validators/referential/__init__.py +80 -0
  769. truthound/validators/referential/base.py +395 -0
  770. truthound/validators/referential/cascade.py +391 -0
  771. truthound/validators/referential/circular.py +563 -0
  772. truthound/validators/referential/foreign_key.py +624 -0
  773. truthound/validators/referential/orphan.py +485 -0
  774. truthound/validators/registry.py +112 -0
  775. truthound/validators/schema/__init__.py +41 -0
  776. truthound/validators/schema/column_count.py +142 -0
  777. truthound/validators/schema/column_exists.py +80 -0
  778. truthound/validators/schema/column_order.py +82 -0
  779. truthound/validators/schema/column_pair.py +85 -0
  780. truthound/validators/schema/column_pair_set.py +195 -0
  781. truthound/validators/schema/column_type.py +94 -0
  782. truthound/validators/schema/multi_column.py +53 -0
  783. truthound/validators/schema/multi_column_aggregate.py +175 -0
  784. truthound/validators/schema/referential.py +274 -0
  785. truthound/validators/schema/table_schema.py +91 -0
  786. truthound/validators/schema_validator.py +219 -0
  787. truthound/validators/sdk/__init__.py +250 -0
  788. truthound/validators/sdk/builder.py +680 -0
  789. truthound/validators/sdk/decorators.py +474 -0
  790. truthound/validators/sdk/enterprise/__init__.py +211 -0
  791. truthound/validators/sdk/enterprise/docs.py +725 -0
  792. truthound/validators/sdk/enterprise/fuzzing.py +659 -0
  793. truthound/validators/sdk/enterprise/licensing.py +709 -0
  794. truthound/validators/sdk/enterprise/manager.py +543 -0
  795. truthound/validators/sdk/enterprise/resources.py +628 -0
  796. truthound/validators/sdk/enterprise/sandbox.py +766 -0
  797. truthound/validators/sdk/enterprise/signing.py +603 -0
  798. truthound/validators/sdk/enterprise/templates.py +865 -0
  799. truthound/validators/sdk/enterprise/versioning.py +659 -0
  800. truthound/validators/sdk/templates.py +757 -0
  801. truthound/validators/sdk/testing.py +807 -0
  802. truthound/validators/security/__init__.py +181 -0
  803. truthound/validators/security/redos/__init__.py +182 -0
  804. truthound/validators/security/redos/core.py +861 -0
  805. truthound/validators/security/redos/cpu_monitor.py +593 -0
  806. truthound/validators/security/redos/cve_database.py +791 -0
  807. truthound/validators/security/redos/ml/__init__.py +155 -0
  808. truthound/validators/security/redos/ml/base.py +785 -0
  809. truthound/validators/security/redos/ml/datasets.py +618 -0
  810. truthound/validators/security/redos/ml/features.py +359 -0
  811. truthound/validators/security/redos/ml/models.py +1000 -0
  812. truthound/validators/security/redos/ml/predictor.py +507 -0
  813. truthound/validators/security/redos/ml/storage.py +632 -0
  814. truthound/validators/security/redos/ml/training.py +571 -0
  815. truthound/validators/security/redos/ml_analyzer.py +937 -0
  816. truthound/validators/security/redos/optimizer.py +674 -0
  817. truthound/validators/security/redos/profiler.py +682 -0
  818. truthound/validators/security/redos/re2_engine.py +709 -0
  819. truthound/validators/security/redos.py +886 -0
  820. truthound/validators/security/sql_security.py +1247 -0
  821. truthound/validators/streaming/__init__.py +126 -0
  822. truthound/validators/streaming/base.py +292 -0
  823. truthound/validators/streaming/completeness.py +210 -0
  824. truthound/validators/streaming/mixin.py +575 -0
  825. truthound/validators/streaming/range.py +308 -0
  826. truthound/validators/streaming/sources.py +846 -0
  827. truthound/validators/string/__init__.py +57 -0
  828. truthound/validators/string/casing.py +158 -0
  829. truthound/validators/string/charset.py +96 -0
  830. truthound/validators/string/format.py +501 -0
  831. truthound/validators/string/json.py +77 -0
  832. truthound/validators/string/json_schema.py +184 -0
  833. truthound/validators/string/length.py +104 -0
  834. truthound/validators/string/like_pattern.py +237 -0
  835. truthound/validators/string/regex.py +202 -0
  836. truthound/validators/string/regex_extended.py +435 -0
  837. truthound/validators/table/__init__.py +88 -0
  838. truthound/validators/table/base.py +78 -0
  839. truthound/validators/table/column_count.py +198 -0
  840. truthound/validators/table/freshness.py +362 -0
  841. truthound/validators/table/row_count.py +251 -0
  842. truthound/validators/table/schema.py +333 -0
  843. truthound/validators/table/size.py +285 -0
  844. truthound/validators/timeout/__init__.py +102 -0
  845. truthound/validators/timeout/advanced/__init__.py +247 -0
  846. truthound/validators/timeout/advanced/circuit_breaker.py +675 -0
  847. truthound/validators/timeout/advanced/prediction.py +773 -0
  848. truthound/validators/timeout/advanced/priority.py +618 -0
  849. truthound/validators/timeout/advanced/redis_backend.py +770 -0
  850. truthound/validators/timeout/advanced/retry.py +721 -0
  851. truthound/validators/timeout/advanced/sampling.py +788 -0
  852. truthound/validators/timeout/advanced/sla.py +661 -0
  853. truthound/validators/timeout/advanced/telemetry.py +804 -0
  854. truthound/validators/timeout/cascade.py +477 -0
  855. truthound/validators/timeout/deadline.py +657 -0
  856. truthound/validators/timeout/degradation.py +525 -0
  857. truthound/validators/timeout/distributed.py +597 -0
  858. truthound/validators/timeseries/__init__.py +89 -0
  859. truthound/validators/timeseries/base.py +326 -0
  860. truthound/validators/timeseries/completeness.py +617 -0
  861. truthound/validators/timeseries/gap.py +485 -0
  862. truthound/validators/timeseries/monotonic.py +310 -0
  863. truthound/validators/timeseries/seasonality.py +422 -0
  864. truthound/validators/timeseries/trend.py +510 -0
  865. truthound/validators/uniqueness/__init__.py +59 -0
  866. truthound/validators/uniqueness/approximate.py +475 -0
  867. truthound/validators/uniqueness/distinct_values.py +253 -0
  868. truthound/validators/uniqueness/duplicate.py +118 -0
  869. truthound/validators/uniqueness/primary_key.py +140 -0
  870. truthound/validators/uniqueness/unique.py +191 -0
  871. truthound/validators/uniqueness/within_record.py +599 -0
  872. truthound/validators/utils.py +756 -0
  873. truthound-1.0.8.dist-info/METADATA +474 -0
  874. truthound-1.0.8.dist-info/RECORD +877 -0
  875. truthound-1.0.8.dist-info/WHEEL +4 -0
  876. truthound-1.0.8.dist-info/entry_points.txt +2 -0
  877. truthound-1.0.8.dist-info/licenses/LICENSE +190 -0
@@ -0,0 +1,952 @@
1
+ """Base classes, protocols, and types for encryption system.
2
+
3
+ This module defines the core abstractions that all encryption implementations
4
+ must follow. It uses Protocol-based structural typing for maximum flexibility
5
+ and follows the same architectural patterns as the compression module.
6
+
7
+ Security Considerations:
8
+ - All symmetric encryption uses authenticated encryption (AEAD)
9
+ - Nonces are generated cryptographically and never reused
10
+ - Keys are derived using strong KDFs (Argon2, PBKDF2, scrypt)
11
+ - Memory is cleared after use where possible
12
+ - Timing-safe comparisons for authentication tags
13
+
14
+ Example:
15
+ >>> from truthound.stores.encryption.base import (
16
+ ... EncryptionAlgorithm,
17
+ ... EncryptionConfig,
18
+ ... )
19
+ >>>
20
+ >>> config = EncryptionConfig(
21
+ ... algorithm=EncryptionAlgorithm.AES_256_GCM,
22
+ ... key_derivation=KeyDerivation.ARGON2ID,
23
+ ... )
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ from abc import ABC, abstractmethod
29
+ from dataclasses import dataclass, field
30
+ from datetime import datetime, timezone
31
+ from enum import Enum, auto
32
+ from typing import (
33
+ Any,
34
+ BinaryIO,
35
+ Callable,
36
+ Iterator,
37
+ Protocol,
38
+ TypeVar,
39
+ runtime_checkable,
40
+ )
41
+ import hashlib
42
+ import hmac
43
+ import os
44
+
45
+
46
+ # =============================================================================
47
+ # Exceptions
48
+ # =============================================================================
49
+
50
+
51
+ class EncryptionError(Exception):
52
+ """Base exception for encryption errors."""
53
+
54
+ def __init__(self, message: str, algorithm: str | None = None) -> None:
55
+ self.algorithm = algorithm
56
+ super().__init__(f"[{algorithm}] {message}" if algorithm else message)
57
+
58
+
59
+ class DecryptionError(EncryptionError):
60
+ """Error during decryption (authentication failure, corrupted data)."""
61
+
62
+ pass
63
+
64
+
65
+ class KeyError_(EncryptionError):
66
+ """Error related to encryption keys (invalid, expired, not found)."""
67
+
68
+ pass
69
+
70
+
71
+ class KeyDerivationError(EncryptionError):
72
+ """Error during key derivation."""
73
+
74
+ pass
75
+
76
+
77
+ class UnsupportedAlgorithmError(EncryptionError):
78
+ """Requested encryption algorithm is not available."""
79
+
80
+ def __init__(self, algorithm: str, available: list[str] | None = None) -> None:
81
+ self.available = available or []
82
+ msg = f"Algorithm '{algorithm}' is not supported"
83
+ if self.available:
84
+ msg += f". Available: {', '.join(self.available)}"
85
+ super().__init__(msg, algorithm)
86
+
87
+
88
+ class EncryptionConfigError(EncryptionError):
89
+ """Invalid encryption configuration."""
90
+
91
+ pass
92
+
93
+
94
+ class NonceReuseError(EncryptionError):
95
+ """Attempted nonce reuse detected (critical security error)."""
96
+
97
+ pass
98
+
99
+
100
+ class KeyExpiredError(KeyError_):
101
+ """Encryption key has expired."""
102
+
103
+ pass
104
+
105
+
106
+ class IntegrityError(DecryptionError):
107
+ """Data integrity verification failed."""
108
+
109
+ pass
110
+
111
+
112
+ # =============================================================================
113
+ # Enums
114
+ # =============================================================================
115
+
116
+
117
+ class EncryptionAlgorithm(str, Enum):
118
+ """Supported encryption algorithms.
119
+
120
+ All algorithms use authenticated encryption (AEAD) to provide both
121
+ confidentiality and integrity protection.
122
+ """
123
+
124
+ # AES-GCM variants (recommended for most use cases)
125
+ AES_128_GCM = "aes-128-gcm"
126
+ AES_256_GCM = "aes-256-gcm"
127
+
128
+ # ChaCha20-Poly1305 (better for software implementations)
129
+ CHACHA20_POLY1305 = "chacha20-poly1305"
130
+
131
+ # Fernet (high-level, batteries-included)
132
+ FERNET = "fernet"
133
+
134
+ # XChaCha20-Poly1305 (extended nonce for random generation)
135
+ XCHACHA20_POLY1305 = "xchacha20-poly1305"
136
+
137
+ # No encryption (for testing/development)
138
+ NONE = "none"
139
+
140
+ @property
141
+ def key_size(self) -> int:
142
+ """Get key size in bytes."""
143
+ key_sizes = {
144
+ self.AES_128_GCM: 16,
145
+ self.AES_256_GCM: 32,
146
+ self.CHACHA20_POLY1305: 32,
147
+ self.XCHACHA20_POLY1305: 32,
148
+ self.FERNET: 32,
149
+ self.NONE: 0,
150
+ }
151
+ return key_sizes.get(self, 32)
152
+
153
+ @property
154
+ def nonce_size(self) -> int:
155
+ """Get nonce/IV size in bytes."""
156
+ nonce_sizes = {
157
+ self.AES_128_GCM: 12,
158
+ self.AES_256_GCM: 12,
159
+ self.CHACHA20_POLY1305: 12,
160
+ self.XCHACHA20_POLY1305: 24,
161
+ self.FERNET: 16,
162
+ self.NONE: 0,
163
+ }
164
+ return nonce_sizes.get(self, 12)
165
+
166
+ @property
167
+ def tag_size(self) -> int:
168
+ """Get authentication tag size in bytes."""
169
+ tag_sizes = {
170
+ self.AES_128_GCM: 16,
171
+ self.AES_256_GCM: 16,
172
+ self.CHACHA20_POLY1305: 16,
173
+ self.XCHACHA20_POLY1305: 16,
174
+ self.FERNET: 32, # HMAC-SHA256
175
+ self.NONE: 0,
176
+ }
177
+ return tag_sizes.get(self, 16)
178
+
179
+ @property
180
+ def is_aead(self) -> bool:
181
+ """Check if algorithm provides authenticated encryption."""
182
+ return self != self.NONE
183
+
184
+
185
+ class KeyDerivation(str, Enum):
186
+ """Key derivation functions for password-based encryption."""
187
+
188
+ # Argon2 variants (recommended)
189
+ ARGON2ID = "argon2id"
190
+ ARGON2I = "argon2i"
191
+ ARGON2D = "argon2d"
192
+
193
+ # PBKDF2 (widely compatible)
194
+ PBKDF2_SHA256 = "pbkdf2-sha256"
195
+ PBKDF2_SHA512 = "pbkdf2-sha512"
196
+
197
+ # scrypt (memory-hard)
198
+ SCRYPT = "scrypt"
199
+
200
+ # HKDF (for key expansion, not password derivation)
201
+ HKDF_SHA256 = "hkdf-sha256"
202
+ HKDF_SHA512 = "hkdf-sha512"
203
+
204
+ # Direct key (no derivation)
205
+ NONE = "none"
206
+
207
+ @property
208
+ def is_password_based(self) -> bool:
209
+ """Check if this KDF is suitable for password-based key derivation."""
210
+ return self in (
211
+ self.ARGON2ID,
212
+ self.ARGON2I,
213
+ self.ARGON2D,
214
+ self.PBKDF2_SHA256,
215
+ self.PBKDF2_SHA512,
216
+ self.SCRYPT,
217
+ )
218
+
219
+ @property
220
+ def default_iterations(self) -> int:
221
+ """Get default iteration count for this KDF."""
222
+ iterations = {
223
+ self.PBKDF2_SHA256: 600_000,
224
+ self.PBKDF2_SHA512: 210_000,
225
+ self.ARGON2ID: 3,
226
+ self.ARGON2I: 4,
227
+ self.ARGON2D: 3,
228
+ self.SCRYPT: 1,
229
+ }
230
+ return iterations.get(self, 1)
231
+
232
+
233
+ class KeyType(str, Enum):
234
+ """Types of encryption keys."""
235
+
236
+ # Symmetric keys
237
+ SYMMETRIC = "symmetric"
238
+ DATA_ENCRYPTION_KEY = "dek"
239
+ KEY_ENCRYPTION_KEY = "kek"
240
+
241
+ # For envelope encryption
242
+ MASTER_KEY = "master"
243
+ DERIVED_KEY = "derived"
244
+
245
+ # Session keys
246
+ SESSION = "session"
247
+ EPHEMERAL = "ephemeral"
248
+
249
+
250
+ class EncryptionMode(Enum):
251
+ """Encryption operation mode."""
252
+
253
+ ENCRYPT = auto()
254
+ DECRYPT = auto()
255
+ BOTH = auto()
256
+
257
+
258
+ # =============================================================================
259
+ # Data Classes
260
+ # =============================================================================
261
+
262
+
263
+ @dataclass
264
+ class KeyDerivationConfig:
265
+ """Configuration for key derivation.
266
+
267
+ Attributes:
268
+ kdf: Key derivation function to use.
269
+ salt_size: Size of salt in bytes.
270
+ iterations: Number of iterations (for PBKDF2).
271
+ memory_cost: Memory cost in KiB (for Argon2).
272
+ parallelism: Degree of parallelism (for Argon2).
273
+ time_cost: Time cost / iterations (for Argon2).
274
+ n: CPU/memory cost parameter (for scrypt).
275
+ r: Block size parameter (for scrypt).
276
+ p: Parallelization parameter (for scrypt).
277
+ """
278
+
279
+ kdf: KeyDerivation = KeyDerivation.ARGON2ID
280
+ salt_size: int = 16
281
+ iterations: int | None = None # Uses KDF default if None
282
+ memory_cost: int = 65536 # 64 MiB for Argon2
283
+ parallelism: int = 4
284
+ time_cost: int = 3
285
+ n: int = 2**14 # scrypt CPU/memory cost
286
+ r: int = 8 # scrypt block size
287
+ p: int = 1 # scrypt parallelism
288
+
289
+ def get_iterations(self) -> int:
290
+ """Get effective iterations count."""
291
+ return self.iterations or self.kdf.default_iterations
292
+
293
+ def validate(self) -> None:
294
+ """Validate configuration."""
295
+ if self.salt_size < 8:
296
+ raise EncryptionConfigError("salt_size must be at least 8 bytes")
297
+ if self.memory_cost < 8:
298
+ raise EncryptionConfigError("memory_cost must be at least 8 KiB")
299
+ if self.parallelism < 1:
300
+ raise EncryptionConfigError("parallelism must be at least 1")
301
+
302
+
303
+ @dataclass
304
+ class EncryptionConfig:
305
+ """Configuration for encryption operations.
306
+
307
+ Attributes:
308
+ algorithm: Encryption algorithm to use.
309
+ key_derivation: Key derivation configuration.
310
+ chunk_size: Size of chunks for streaming encryption.
311
+ include_header: Include metadata header in encrypted output.
312
+ verify_on_decrypt: Verify integrity on decryption (always true for AEAD).
313
+ associated_data: Additional authenticated data (AAD).
314
+ key_id: Identifier for the encryption key (for key management).
315
+ """
316
+
317
+ algorithm: EncryptionAlgorithm = EncryptionAlgorithm.AES_256_GCM
318
+ key_derivation: KeyDerivationConfig = field(default_factory=KeyDerivationConfig)
319
+ chunk_size: int = 64 * 1024 # 64KB
320
+ include_header: bool = True
321
+ verify_on_decrypt: bool = True
322
+ associated_data: bytes | None = None
323
+ key_id: str | None = None
324
+
325
+ def validate(self) -> None:
326
+ """Validate configuration."""
327
+ if self.chunk_size <= 0:
328
+ raise EncryptionConfigError("chunk_size must be positive")
329
+ self.key_derivation.validate()
330
+
331
+
332
+ @dataclass
333
+ class EncryptionKey:
334
+ """Represents an encryption key with metadata.
335
+
336
+ Attributes:
337
+ key_id: Unique identifier for this key.
338
+ key_material: The actual key bytes (should be cleared after use).
339
+ algorithm: Algorithm this key is for.
340
+ key_type: Type of key.
341
+ created_at: When the key was created.
342
+ expires_at: When the key expires (None = never).
343
+ version: Key version for rotation tracking.
344
+ metadata: Additional key metadata.
345
+ """
346
+
347
+ key_id: str
348
+ key_material: bytes
349
+ algorithm: EncryptionAlgorithm
350
+ key_type: KeyType = KeyType.DATA_ENCRYPTION_KEY
351
+ created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
352
+ expires_at: datetime | None = None
353
+ version: int = 1
354
+ metadata: dict[str, Any] = field(default_factory=dict)
355
+
356
+ def __post_init__(self) -> None:
357
+ """Validate key after creation."""
358
+ expected_size = self.algorithm.key_size
359
+ if expected_size > 0 and len(self.key_material) != expected_size:
360
+ raise KeyError_(
361
+ f"Key size mismatch: expected {expected_size} bytes, "
362
+ f"got {len(self.key_material)} bytes",
363
+ self.algorithm.value,
364
+ )
365
+
366
+ @property
367
+ def is_expired(self) -> bool:
368
+ """Check if key has expired."""
369
+ if self.expires_at is None:
370
+ return False
371
+ return datetime.now(timezone.utc) > self.expires_at
372
+
373
+ def validate(self) -> None:
374
+ """Validate key is usable."""
375
+ if self.is_expired:
376
+ raise KeyExpiredError(
377
+ f"Key '{self.key_id}' expired at {self.expires_at}",
378
+ self.algorithm.value,
379
+ )
380
+
381
+ def clear(self) -> None:
382
+ """Clear key material from memory (best-effort)."""
383
+ if self.key_material:
384
+ # Overwrite with zeros (best-effort, Python may have copies)
385
+ self.key_material = b"\x00" * len(self.key_material)
386
+
387
+ def to_dict(self, include_key: bool = False) -> dict[str, Any]:
388
+ """Convert to dictionary (optionally excluding key material)."""
389
+ result = {
390
+ "key_id": self.key_id,
391
+ "algorithm": self.algorithm.value,
392
+ "key_type": self.key_type.value,
393
+ "created_at": self.created_at.isoformat(),
394
+ "expires_at": self.expires_at.isoformat() if self.expires_at else None,
395
+ "version": self.version,
396
+ "metadata": self.metadata,
397
+ }
398
+ if include_key:
399
+ import base64
400
+
401
+ result["key_material"] = base64.b64encode(self.key_material).decode()
402
+ return result
403
+
404
+
405
+ @dataclass
406
+ class EncryptionMetrics:
407
+ """Metrics from an encryption operation.
408
+
409
+ Attributes:
410
+ plaintext_size: Size of plaintext data in bytes.
411
+ ciphertext_size: Size of ciphertext data in bytes.
412
+ overhead_bytes: Encryption overhead (nonce + tag).
413
+ encryption_time_ms: Time taken to encrypt in milliseconds.
414
+ decryption_time_ms: Time taken to decrypt in milliseconds.
415
+ algorithm: Algorithm used.
416
+ key_derivation_time_ms: Time for key derivation (if applicable).
417
+ """
418
+
419
+ plaintext_size: int = 0
420
+ ciphertext_size: int = 0
421
+ overhead_bytes: int = 0
422
+ encryption_time_ms: float = 0.0
423
+ decryption_time_ms: float = 0.0
424
+ algorithm: EncryptionAlgorithm = EncryptionAlgorithm.NONE
425
+ key_derivation_time_ms: float = 0.0
426
+
427
+ @property
428
+ def overhead_percent(self) -> float:
429
+ """Calculate overhead percentage."""
430
+ if self.plaintext_size == 0:
431
+ return 0.0
432
+ return (self.overhead_bytes / self.plaintext_size) * 100
433
+
434
+ @property
435
+ def throughput_encrypt_mbps(self) -> float:
436
+ """Calculate encryption throughput in MB/s."""
437
+ if self.encryption_time_ms == 0:
438
+ return 0.0
439
+ return (self.plaintext_size / 1024 / 1024) / (self.encryption_time_ms / 1000)
440
+
441
+ @property
442
+ def throughput_decrypt_mbps(self) -> float:
443
+ """Calculate decryption throughput in MB/s."""
444
+ if self.decryption_time_ms == 0:
445
+ return 0.0
446
+ return (self.plaintext_size / 1024 / 1024) / (self.decryption_time_ms / 1000)
447
+
448
+ def to_dict(self) -> dict[str, Any]:
449
+ """Convert to dictionary."""
450
+ return {
451
+ "plaintext_size": self.plaintext_size,
452
+ "ciphertext_size": self.ciphertext_size,
453
+ "overhead_bytes": self.overhead_bytes,
454
+ "overhead_percent": round(self.overhead_percent, 2),
455
+ "encryption_time_ms": round(self.encryption_time_ms, 2),
456
+ "decryption_time_ms": round(self.decryption_time_ms, 2),
457
+ "throughput_encrypt_mbps": round(self.throughput_encrypt_mbps, 2),
458
+ "throughput_decrypt_mbps": round(self.throughput_decrypt_mbps, 2),
459
+ "algorithm": self.algorithm.value,
460
+ "key_derivation_time_ms": round(self.key_derivation_time_ms, 2),
461
+ }
462
+
463
+
464
+ @dataclass
465
+ class EncryptionResult:
466
+ """Result of an encryption operation.
467
+
468
+ Attributes:
469
+ ciphertext: Encrypted data bytes.
470
+ nonce: Nonce/IV used for encryption.
471
+ tag: Authentication tag.
472
+ metrics: Encryption metrics.
473
+ header: Optional metadata header.
474
+ key_id: ID of key used (for key management).
475
+ """
476
+
477
+ ciphertext: bytes
478
+ nonce: bytes
479
+ tag: bytes
480
+ metrics: EncryptionMetrics
481
+ header: dict[str, Any] = field(default_factory=dict)
482
+ key_id: str | None = None
483
+
484
+ def to_bytes(self, include_header: bool = False) -> bytes:
485
+ """Serialize to bytes format.
486
+
487
+ Format: [header_len (4 bytes)][header_json][nonce][ciphertext][tag]
488
+ Or without header: [nonce][ciphertext][tag]
489
+ """
490
+ import json
491
+
492
+ if include_header and self.header:
493
+ header_bytes = json.dumps(self.header).encode()
494
+ header_len = len(header_bytes).to_bytes(4, "big")
495
+ return header_len + header_bytes + self.nonce + self.ciphertext + self.tag
496
+ return self.nonce + self.ciphertext + self.tag
497
+
498
+ @classmethod
499
+ def from_bytes(
500
+ cls,
501
+ data: bytes,
502
+ algorithm: EncryptionAlgorithm,
503
+ has_header: bool = False,
504
+ ) -> "EncryptionResult":
505
+ """Deserialize from bytes format."""
506
+ import json
507
+
508
+ header: dict[str, Any] = {}
509
+ offset = 0
510
+
511
+ if has_header:
512
+ header_len = int.from_bytes(data[:4], "big")
513
+ offset = 4
514
+ header = json.loads(data[offset : offset + header_len].decode())
515
+ offset += header_len
516
+
517
+ nonce_size = algorithm.nonce_size
518
+ tag_size = algorithm.tag_size
519
+
520
+ nonce = data[offset : offset + nonce_size]
521
+ offset += nonce_size
522
+
523
+ ciphertext = data[offset : -tag_size] if tag_size > 0 else data[offset:]
524
+ tag = data[-tag_size:] if tag_size > 0 else b""
525
+
526
+ return cls(
527
+ ciphertext=ciphertext,
528
+ nonce=nonce,
529
+ tag=tag,
530
+ metrics=EncryptionMetrics(algorithm=algorithm),
531
+ header=header,
532
+ )
533
+
534
+
535
+ @dataclass
536
+ class EncryptionStats:
537
+ """Aggregated encryption statistics across multiple operations.
538
+
539
+ Attributes:
540
+ total_operations: Number of encryption operations.
541
+ total_plaintext_bytes: Total bytes encrypted.
542
+ total_ciphertext_bytes: Total bytes of ciphertext.
543
+ total_encryption_time_ms: Total encryption time.
544
+ total_decryption_time_ms: Total decryption time.
545
+ algorithm_usage: Count of each algorithm used.
546
+ errors: Number of errors encountered.
547
+ """
548
+
549
+ total_operations: int = 0
550
+ total_plaintext_bytes: int = 0
551
+ total_ciphertext_bytes: int = 0
552
+ total_encryption_time_ms: float = 0.0
553
+ total_decryption_time_ms: float = 0.0
554
+ algorithm_usage: dict[str, int] = field(default_factory=dict)
555
+ errors: int = 0
556
+
557
+ def record(self, metrics: EncryptionMetrics) -> None:
558
+ """Record metrics from an encryption operation."""
559
+ self.total_operations += 1
560
+ self.total_plaintext_bytes += metrics.plaintext_size
561
+ self.total_ciphertext_bytes += metrics.ciphertext_size
562
+ self.total_encryption_time_ms += metrics.encryption_time_ms
563
+ self.total_decryption_time_ms += metrics.decryption_time_ms
564
+
565
+ algo = metrics.algorithm.value
566
+ self.algorithm_usage[algo] = self.algorithm_usage.get(algo, 0) + 1
567
+
568
+ @property
569
+ def average_overhead(self) -> float:
570
+ """Calculate average overhead percentage."""
571
+ if self.total_plaintext_bytes == 0:
572
+ return 0.0
573
+ overhead = self.total_ciphertext_bytes - self.total_plaintext_bytes
574
+ return (overhead / self.total_plaintext_bytes) * 100
575
+
576
+ def to_dict(self) -> dict[str, Any]:
577
+ """Convert to dictionary."""
578
+ return {
579
+ "total_operations": self.total_operations,
580
+ "total_plaintext_bytes": self.total_plaintext_bytes,
581
+ "total_ciphertext_bytes": self.total_ciphertext_bytes,
582
+ "average_overhead_percent": round(self.average_overhead, 2),
583
+ "total_encryption_time_ms": round(self.total_encryption_time_ms, 2),
584
+ "total_decryption_time_ms": round(self.total_decryption_time_ms, 2),
585
+ "algorithm_usage": self.algorithm_usage,
586
+ "errors": self.errors,
587
+ }
588
+
589
+
590
+ # =============================================================================
591
+ # Header Format
592
+ # =============================================================================
593
+
594
+
595
+ @dataclass
596
+ class EncryptionHeader:
597
+ """Encryption metadata header.
598
+
599
+ This header is prepended to encrypted data to enable self-describing
600
+ encryption format. The header itself is authenticated but not encrypted.
601
+
602
+ Attributes:
603
+ version: Header format version.
604
+ algorithm: Encryption algorithm used.
605
+ kdf: Key derivation function used.
606
+ salt: Salt used for key derivation (if applicable).
607
+ key_id: ID of the key used.
608
+ created_at: Timestamp of encryption.
609
+ nonce_size: Size of nonce in bytes.
610
+ tag_size: Size of authentication tag in bytes.
611
+ extra: Additional metadata.
612
+ """
613
+
614
+ version: int = 1
615
+ algorithm: EncryptionAlgorithm = EncryptionAlgorithm.AES_256_GCM
616
+ kdf: KeyDerivation = KeyDerivation.NONE
617
+ salt: bytes = b""
618
+ key_id: str | None = None
619
+ created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
620
+ nonce_size: int = 12
621
+ tag_size: int = 16
622
+ extra: dict[str, Any] = field(default_factory=dict)
623
+
624
+ def to_bytes(self) -> bytes:
625
+ """Serialize header to bytes."""
626
+ import json
627
+
628
+ data = {
629
+ "v": self.version,
630
+ "alg": self.algorithm.value,
631
+ "kdf": self.kdf.value,
632
+ "salt": self.salt.hex() if self.salt else "",
633
+ "kid": self.key_id,
634
+ "ts": self.created_at.isoformat(),
635
+ "ns": self.nonce_size,
636
+ "ts_": self.tag_size,
637
+ "ext": self.extra,
638
+ }
639
+ header_json = json.dumps(data, separators=(",", ":")).encode()
640
+ return len(header_json).to_bytes(4, "big") + header_json
641
+
642
+ @classmethod
643
+ def from_bytes(cls, data: bytes) -> tuple["EncryptionHeader", int]:
644
+ """Deserialize header from bytes.
645
+
646
+ Returns:
647
+ Tuple of (header, bytes_consumed).
648
+ """
649
+ import json
650
+
651
+ header_len = int.from_bytes(data[:4], "big")
652
+ header_json = data[4 : 4 + header_len]
653
+ d = json.loads(header_json.decode())
654
+
655
+ header = cls(
656
+ version=d["v"],
657
+ algorithm=EncryptionAlgorithm(d["alg"]),
658
+ kdf=KeyDerivation(d["kdf"]),
659
+ salt=bytes.fromhex(d["salt"]) if d["salt"] else b"",
660
+ key_id=d.get("kid"),
661
+ created_at=datetime.fromisoformat(d["ts"]),
662
+ nonce_size=d["ns"],
663
+ tag_size=d["ts_"],
664
+ extra=d.get("ext", {}),
665
+ )
666
+ return header, 4 + header_len
667
+
668
+
669
+ # =============================================================================
670
+ # Protocols
671
+ # =============================================================================
672
+
673
+
674
+ @runtime_checkable
675
+ class Encryptor(Protocol):
676
+ """Protocol for encryption implementations."""
677
+
678
+ @property
679
+ def algorithm(self) -> EncryptionAlgorithm:
680
+ """Get the encryption algorithm."""
681
+ ...
682
+
683
+ def encrypt(self, plaintext: bytes, key: bytes) -> bytes:
684
+ """Encrypt plaintext data.
685
+
686
+ Args:
687
+ plaintext: Data to encrypt.
688
+ key: Encryption key.
689
+
690
+ Returns:
691
+ Encrypted data (nonce + ciphertext + tag).
692
+ """
693
+ ...
694
+
695
+ def encrypt_with_metrics(
696
+ self,
697
+ plaintext: bytes,
698
+ key: bytes,
699
+ aad: bytes | None = None,
700
+ ) -> EncryptionResult:
701
+ """Encrypt data and return detailed result with metrics.
702
+
703
+ Args:
704
+ plaintext: Data to encrypt.
705
+ key: Encryption key.
706
+ aad: Additional authenticated data.
707
+
708
+ Returns:
709
+ Encryption result with metrics.
710
+ """
711
+ ...
712
+
713
+
714
+ @runtime_checkable
715
+ class Decryptor(Protocol):
716
+ """Protocol for decryption implementations."""
717
+
718
+ @property
719
+ def algorithm(self) -> EncryptionAlgorithm:
720
+ """Get the encryption algorithm."""
721
+ ...
722
+
723
+ def decrypt(self, ciphertext: bytes, key: bytes) -> bytes:
724
+ """Decrypt ciphertext data.
725
+
726
+ Args:
727
+ ciphertext: Data to decrypt (nonce + ciphertext + tag).
728
+ key: Decryption key.
729
+
730
+ Returns:
731
+ Decrypted plaintext.
732
+
733
+ Raises:
734
+ DecryptionError: If decryption or authentication fails.
735
+ """
736
+ ...
737
+
738
+
739
+ @runtime_checkable
740
+ class KeyDeriver(Protocol):
741
+ """Protocol for key derivation implementations."""
742
+
743
+ def derive_key(
744
+ self,
745
+ password: str | bytes,
746
+ salt: bytes,
747
+ key_size: int,
748
+ ) -> bytes:
749
+ """Derive a key from password/passphrase.
750
+
751
+ Args:
752
+ password: Password or passphrase.
753
+ salt: Cryptographic salt.
754
+ key_size: Desired key size in bytes.
755
+
756
+ Returns:
757
+ Derived key.
758
+ """
759
+ ...
760
+
761
+
762
+ @runtime_checkable
763
+ class StreamingEncryptor(Protocol):
764
+ """Protocol for streaming encryption."""
765
+
766
+ def write(self, data: bytes) -> bytes:
767
+ """Write data to encryption stream.
768
+
769
+ Args:
770
+ data: Plaintext chunk to encrypt.
771
+
772
+ Returns:
773
+ Encrypted data (may be buffered).
774
+ """
775
+ ...
776
+
777
+ def flush(self) -> bytes:
778
+ """Flush buffered data.
779
+
780
+ Returns:
781
+ Encrypted data from buffer.
782
+ """
783
+ ...
784
+
785
+ def finalize(self) -> bytes:
786
+ """Finalize encryption and get remaining data with tag.
787
+
788
+ Returns:
789
+ Final encrypted data including authentication tag.
790
+ """
791
+ ...
792
+
793
+
794
+ @runtime_checkable
795
+ class StreamingDecryptor(Protocol):
796
+ """Protocol for streaming decryption."""
797
+
798
+ def write(self, data: bytes) -> bytes:
799
+ """Write encrypted data and get decrypted output.
800
+
801
+ Args:
802
+ data: Ciphertext chunk.
803
+
804
+ Returns:
805
+ Decrypted plaintext.
806
+ """
807
+ ...
808
+
809
+ def finalize(self) -> bytes:
810
+ """Finalize decryption and verify authentication.
811
+
812
+ Returns:
813
+ Any remaining decrypted data.
814
+
815
+ Raises:
816
+ IntegrityError: If authentication fails.
817
+ """
818
+ ...
819
+
820
+
821
+ @runtime_checkable
822
+ class KeyManager(Protocol):
823
+ """Protocol for key management."""
824
+
825
+ def get_key(self, key_id: str) -> EncryptionKey:
826
+ """Retrieve a key by ID.
827
+
828
+ Args:
829
+ key_id: Key identifier.
830
+
831
+ Returns:
832
+ Encryption key.
833
+
834
+ Raises:
835
+ KeyError_: If key not found.
836
+ """
837
+ ...
838
+
839
+ def store_key(self, key: EncryptionKey) -> None:
840
+ """Store a key.
841
+
842
+ Args:
843
+ key: Key to store.
844
+ """
845
+ ...
846
+
847
+ def rotate_key(self, key_id: str) -> EncryptionKey:
848
+ """Rotate a key (create new version).
849
+
850
+ Args:
851
+ key_id: Key to rotate.
852
+
853
+ Returns:
854
+ New key version.
855
+ """
856
+ ...
857
+
858
+ def delete_key(self, key_id: str) -> None:
859
+ """Delete a key.
860
+
861
+ Args:
862
+ key_id: Key to delete.
863
+ """
864
+ ...
865
+
866
+
867
+ # =============================================================================
868
+ # Utility Functions
869
+ # =============================================================================
870
+
871
+
872
+ def generate_key(algorithm: EncryptionAlgorithm) -> bytes:
873
+ """Generate a cryptographically secure random key.
874
+
875
+ Args:
876
+ algorithm: Algorithm to generate key for.
877
+
878
+ Returns:
879
+ Random key bytes.
880
+ """
881
+ return os.urandom(algorithm.key_size)
882
+
883
+
884
+ def generate_nonce(algorithm: EncryptionAlgorithm) -> bytes:
885
+ """Generate a cryptographically secure random nonce.
886
+
887
+ Args:
888
+ algorithm: Algorithm to generate nonce for.
889
+
890
+ Returns:
891
+ Random nonce bytes.
892
+ """
893
+ return os.urandom(algorithm.nonce_size)
894
+
895
+
896
+ def generate_salt(size: int = 16) -> bytes:
897
+ """Generate a cryptographically secure random salt.
898
+
899
+ Args:
900
+ size: Salt size in bytes.
901
+
902
+ Returns:
903
+ Random salt bytes.
904
+ """
905
+ return os.urandom(size)
906
+
907
+
908
+ def generate_key_id() -> str:
909
+ """Generate a unique key identifier.
910
+
911
+ Returns:
912
+ Unique key ID string.
913
+ """
914
+ return os.urandom(16).hex()
915
+
916
+
917
+ def constant_time_compare(a: bytes, b: bytes) -> bool:
918
+ """Compare two byte strings in constant time.
919
+
920
+ This prevents timing attacks when comparing authentication tags.
921
+
922
+ Args:
923
+ a: First byte string.
924
+ b: Second byte string.
925
+
926
+ Returns:
927
+ True if equal, False otherwise.
928
+ """
929
+ return hmac.compare_digest(a, b)
930
+
931
+
932
+ def secure_hash(data: bytes, algorithm: str = "sha256") -> str:
933
+ """Compute secure hash of data.
934
+
935
+ Args:
936
+ data: Data to hash.
937
+ algorithm: Hash algorithm name.
938
+
939
+ Returns:
940
+ Hex-encoded hash.
941
+ """
942
+ return hashlib.new(algorithm, data).hexdigest()
943
+
944
+
945
+ # =============================================================================
946
+ # Type Variables
947
+ # =============================================================================
948
+
949
+ T = TypeVar("T")
950
+ EncryptorT = TypeVar("EncryptorT", bound=Encryptor)
951
+ DecryptorT = TypeVar("DecryptorT", bound=Decryptor)
952
+ KeyDeriverT = TypeVar("KeyDeriverT", bound=KeyDeriver)