raxe 0.4.6__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 (668) hide show
  1. raxe/__init__.py +101 -0
  2. raxe/application/__init__.py +48 -0
  3. raxe/application/ab_testing.py +170 -0
  4. raxe/application/analytics/__init__.py +30 -0
  5. raxe/application/analytics/achievement_service.py +444 -0
  6. raxe/application/analytics/repositories.py +172 -0
  7. raxe/application/analytics/retention_service.py +267 -0
  8. raxe/application/analytics/statistics_service.py +419 -0
  9. raxe/application/analytics/streak_service.py +283 -0
  10. raxe/application/apply_policy.py +291 -0
  11. raxe/application/eager_l2.py +503 -0
  12. raxe/application/preloader.py +353 -0
  13. raxe/application/scan_merger.py +321 -0
  14. raxe/application/scan_pipeline.py +1059 -0
  15. raxe/application/scan_pipeline_async.py +403 -0
  16. raxe/application/session_tracker.py +458 -0
  17. raxe/application/telemetry_manager.py +357 -0
  18. raxe/application/telemetry_orchestrator.py +1210 -0
  19. raxe/async_sdk/__init__.py +34 -0
  20. raxe/async_sdk/cache.py +286 -0
  21. raxe/async_sdk/client.py +556 -0
  22. raxe/async_sdk/wrappers/__init__.py +23 -0
  23. raxe/async_sdk/wrappers/openai.py +238 -0
  24. raxe/cli/__init__.py +21 -0
  25. raxe/cli/auth.py +1047 -0
  26. raxe/cli/branding.py +235 -0
  27. raxe/cli/config.py +334 -0
  28. raxe/cli/custom_rules.py +458 -0
  29. raxe/cli/doctor.py +686 -0
  30. raxe/cli/error_handler.py +665 -0
  31. raxe/cli/event.py +648 -0
  32. raxe/cli/exit_codes.py +57 -0
  33. raxe/cli/expiry_warning.py +302 -0
  34. raxe/cli/export.py +183 -0
  35. raxe/cli/history.py +247 -0
  36. raxe/cli/l2_formatter.py +872 -0
  37. raxe/cli/main.py +1137 -0
  38. raxe/cli/models.py +590 -0
  39. raxe/cli/output.py +403 -0
  40. raxe/cli/privacy.py +84 -0
  41. raxe/cli/profiler.py +262 -0
  42. raxe/cli/progress.py +379 -0
  43. raxe/cli/progress_context.py +101 -0
  44. raxe/cli/repl.py +394 -0
  45. raxe/cli/rules.py +542 -0
  46. raxe/cli/setup_wizard.py +721 -0
  47. raxe/cli/stats.py +292 -0
  48. raxe/cli/suppress.py +501 -0
  49. raxe/cli/telemetry.py +1384 -0
  50. raxe/cli/test.py +130 -0
  51. raxe/cli/tune.py +315 -0
  52. raxe/cli/validate.py +218 -0
  53. raxe/domain/__init__.py +30 -0
  54. raxe/domain/analytics/__init__.py +97 -0
  55. raxe/domain/analytics/achievements.py +306 -0
  56. raxe/domain/analytics/models.py +120 -0
  57. raxe/domain/analytics/retention.py +168 -0
  58. raxe/domain/analytics/statistics.py +207 -0
  59. raxe/domain/analytics/streaks.py +173 -0
  60. raxe/domain/engine/__init__.py +15 -0
  61. raxe/domain/engine/executor.py +396 -0
  62. raxe/domain/engine/matcher.py +212 -0
  63. raxe/domain/inline_suppression.py +176 -0
  64. raxe/domain/ml/__init__.py +133 -0
  65. raxe/domain/ml/embedding_cache.py +309 -0
  66. raxe/domain/ml/gemma_detector.py +921 -0
  67. raxe/domain/ml/gemma_models.py +346 -0
  68. raxe/domain/ml/l2_config.py +428 -0
  69. raxe/domain/ml/l2_output_schema.py +443 -0
  70. raxe/domain/ml/manifest_loader.py +309 -0
  71. raxe/domain/ml/manifest_schema.py +345 -0
  72. raxe/domain/ml/model_metadata.py +263 -0
  73. raxe/domain/ml/model_registry.py +786 -0
  74. raxe/domain/ml/protocol.py +282 -0
  75. raxe/domain/ml/scoring_models.py +419 -0
  76. raxe/domain/ml/stub_detector.py +397 -0
  77. raxe/domain/ml/threat_scorer.py +757 -0
  78. raxe/domain/ml/tokenizer_registry.py +372 -0
  79. raxe/domain/ml/voting/__init__.py +89 -0
  80. raxe/domain/ml/voting/config.py +595 -0
  81. raxe/domain/ml/voting/engine.py +465 -0
  82. raxe/domain/ml/voting/head_voters.py +378 -0
  83. raxe/domain/ml/voting/models.py +222 -0
  84. raxe/domain/models.py +82 -0
  85. raxe/domain/packs/__init__.py +17 -0
  86. raxe/domain/packs/models.py +304 -0
  87. raxe/domain/policies/__init__.py +20 -0
  88. raxe/domain/policies/evaluator.py +212 -0
  89. raxe/domain/policies/models.py +223 -0
  90. raxe/domain/rules/__init__.py +32 -0
  91. raxe/domain/rules/custom.py +286 -0
  92. raxe/domain/rules/models.py +273 -0
  93. raxe/domain/rules/schema.py +166 -0
  94. raxe/domain/rules/validator.py +556 -0
  95. raxe/domain/suppression.py +801 -0
  96. raxe/domain/suppression_factory.py +174 -0
  97. raxe/domain/telemetry/__init__.py +116 -0
  98. raxe/domain/telemetry/backpressure.py +424 -0
  99. raxe/domain/telemetry/event_creator.py +362 -0
  100. raxe/domain/telemetry/events.py +1282 -0
  101. raxe/domain/telemetry/priority.py +263 -0
  102. raxe/domain/telemetry/scan_telemetry_builder.py +670 -0
  103. raxe/infrastructure/__init__.py +25 -0
  104. raxe/infrastructure/analytics/__init__.py +18 -0
  105. raxe/infrastructure/analytics/aggregator.py +484 -0
  106. raxe/infrastructure/analytics/aggregator_optimized.py +184 -0
  107. raxe/infrastructure/analytics/engine.py +748 -0
  108. raxe/infrastructure/analytics/repository.py +409 -0
  109. raxe/infrastructure/analytics/streaks.py +467 -0
  110. raxe/infrastructure/analytics/views.py +178 -0
  111. raxe/infrastructure/cloud/__init__.py +9 -0
  112. raxe/infrastructure/config/__init__.py +56 -0
  113. raxe/infrastructure/config/endpoints.py +641 -0
  114. raxe/infrastructure/config/scan_config.py +352 -0
  115. raxe/infrastructure/config/yaml_config.py +459 -0
  116. raxe/infrastructure/database/__init__.py +10 -0
  117. raxe/infrastructure/database/connection.py +200 -0
  118. raxe/infrastructure/database/models.py +325 -0
  119. raxe/infrastructure/database/scan_history.py +764 -0
  120. raxe/infrastructure/ml/__init__.py +0 -0
  121. raxe/infrastructure/ml/download_progress.py +438 -0
  122. raxe/infrastructure/ml/model_downloader.py +457 -0
  123. raxe/infrastructure/models/__init__.py +16 -0
  124. raxe/infrastructure/models/discovery.py +461 -0
  125. raxe/infrastructure/packs/__init__.py +13 -0
  126. raxe/infrastructure/packs/loader.py +407 -0
  127. raxe/infrastructure/packs/registry.py +381 -0
  128. raxe/infrastructure/policies/__init__.py +16 -0
  129. raxe/infrastructure/policies/api_client.py +256 -0
  130. raxe/infrastructure/policies/validator.py +227 -0
  131. raxe/infrastructure/policies/yaml_loader.py +250 -0
  132. raxe/infrastructure/rules/__init__.py +18 -0
  133. raxe/infrastructure/rules/custom_loader.py +224 -0
  134. raxe/infrastructure/rules/versioning.py +222 -0
  135. raxe/infrastructure/rules/yaml_loader.py +286 -0
  136. raxe/infrastructure/security/__init__.py +31 -0
  137. raxe/infrastructure/security/auth.py +145 -0
  138. raxe/infrastructure/security/policy_validator.py +124 -0
  139. raxe/infrastructure/security/signatures.py +171 -0
  140. raxe/infrastructure/suppression/__init__.py +36 -0
  141. raxe/infrastructure/suppression/composite_repository.py +154 -0
  142. raxe/infrastructure/suppression/sqlite_repository.py +231 -0
  143. raxe/infrastructure/suppression/yaml_composite_repository.py +156 -0
  144. raxe/infrastructure/suppression/yaml_repository.py +510 -0
  145. raxe/infrastructure/telemetry/__init__.py +79 -0
  146. raxe/infrastructure/telemetry/acquisition.py +179 -0
  147. raxe/infrastructure/telemetry/config.py +254 -0
  148. raxe/infrastructure/telemetry/credential_store.py +947 -0
  149. raxe/infrastructure/telemetry/dual_queue.py +1123 -0
  150. raxe/infrastructure/telemetry/flush_helper.py +343 -0
  151. raxe/infrastructure/telemetry/flush_scheduler.py +776 -0
  152. raxe/infrastructure/telemetry/health_client.py +394 -0
  153. raxe/infrastructure/telemetry/hook.py +347 -0
  154. raxe/infrastructure/telemetry/queue.py +520 -0
  155. raxe/infrastructure/telemetry/sender.py +476 -0
  156. raxe/infrastructure/tracking/__init__.py +13 -0
  157. raxe/infrastructure/tracking/usage.py +389 -0
  158. raxe/integrations/__init__.py +55 -0
  159. raxe/integrations/availability.py +143 -0
  160. raxe/integrations/registry.py +122 -0
  161. raxe/integrations/utils.py +135 -0
  162. raxe/mcp/__init__.py +62 -0
  163. raxe/mcp/cli.py +97 -0
  164. raxe/mcp/server.py +409 -0
  165. raxe/monitoring/__init__.py +51 -0
  166. raxe/monitoring/metrics.py +372 -0
  167. raxe/monitoring/profiler.py +388 -0
  168. raxe/monitoring/server.py +136 -0
  169. raxe/packs/core/v1.0.0/pack.yaml +1394 -0
  170. raxe/packs/core/v1.0.0/rules/PI/pi-001@1.0.0.yaml +49 -0
  171. raxe/packs/core/v1.0.0/rules/PI/pi-006@1.0.0.yaml +48 -0
  172. raxe/packs/core/v1.0.0/rules/PI/pi-014@1.0.0.yaml +54 -0
  173. raxe/packs/core/v1.0.0/rules/PI/pi-017@1.0.0.yaml +52 -0
  174. raxe/packs/core/v1.0.0/rules/PI/pi-022@1.0.0.yaml +67 -0
  175. raxe/packs/core/v1.0.0/rules/PI/pi-023@1.0.0.yaml +91 -0
  176. raxe/packs/core/v1.0.0/rules/PI/pi-024@1.0.0.yaml +80 -0
  177. raxe/packs/core/v1.0.0/rules/PI/pi-025@1.0.0.yaml +81 -0
  178. raxe/packs/core/v1.0.0/rules/PI/pi-026@1.0.0.yaml +50 -0
  179. raxe/packs/core/v1.0.0/rules/PI/pi-027@1.0.0.yaml +77 -0
  180. raxe/packs/core/v1.0.0/rules/PI/pi-028@1.0.0.yaml +52 -0
  181. raxe/packs/core/v1.0.0/rules/PI/pi-029@1.0.0.yaml +51 -0
  182. raxe/packs/core/v1.0.0/rules/PI/pi-030@1.0.0.yaml +55 -0
  183. raxe/packs/core/v1.0.0/rules/PI/pi-033@1.0.0.yaml +50 -0
  184. raxe/packs/core/v1.0.0/rules/PI/pi-034@1.0.0.yaml +50 -0
  185. raxe/packs/core/v1.0.0/rules/PI/pi-035@1.0.0.yaml +50 -0
  186. raxe/packs/core/v1.0.0/rules/PI/pi-046@1.0.0.yaml +50 -0
  187. raxe/packs/core/v1.0.0/rules/PI/pi-047@1.0.0.yaml +50 -0
  188. raxe/packs/core/v1.0.0/rules/PI/pi-048@1.0.0.yaml +50 -0
  189. raxe/packs/core/v1.0.0/rules/PI/pi-049@1.0.0.yaml +50 -0
  190. raxe/packs/core/v1.0.0/rules/PI/pi-050@1.0.0.yaml +50 -0
  191. raxe/packs/core/v1.0.0/rules/PI/pi-068@1.0.0.yaml +50 -0
  192. raxe/packs/core/v1.0.0/rules/PI/pi-078@1.0.0.yaml +50 -0
  193. raxe/packs/core/v1.0.0/rules/PI/pi-2001@1.0.0.yaml +35 -0
  194. raxe/packs/core/v1.0.0/rules/PI/pi-2004@1.0.0.yaml +39 -0
  195. raxe/packs/core/v1.0.0/rules/PI/pi-201@1.0.0.yaml +43 -0
  196. raxe/packs/core/v1.0.0/rules/PI/pi-202@1.0.0.yaml +47 -0
  197. raxe/packs/core/v1.0.0/rules/PI/pi-203@1.0.0.yaml +46 -0
  198. raxe/packs/core/v1.0.0/rules/PI/pi-3007@1.0.0.yaml +44 -0
  199. raxe/packs/core/v1.0.0/rules/PI/pi-3016@1.0.0.yaml +44 -0
  200. raxe/packs/core/v1.0.0/rules/PI/pi-3026@1.0.0.yaml +39 -0
  201. raxe/packs/core/v1.0.0/rules/PI/pi-3027@1.0.0.yaml +64 -0
  202. raxe/packs/core/v1.0.0/rules/PI/pi-3028@1.0.0.yaml +51 -0
  203. raxe/packs/core/v1.0.0/rules/PI/pi-3029@1.0.0.yaml +53 -0
  204. raxe/packs/core/v1.0.0/rules/PI/pi-3030@1.0.0.yaml +50 -0
  205. raxe/packs/core/v1.0.0/rules/PI/pi-3031@1.0.0.yaml +50 -0
  206. raxe/packs/core/v1.0.0/rules/PI/pi-3032@1.0.0.yaml +50 -0
  207. raxe/packs/core/v1.0.0/rules/PI/pi-3033@1.0.0.yaml +56 -0
  208. raxe/packs/core/v1.0.0/rules/PI/pi-3034@1.0.0.yaml +50 -0
  209. raxe/packs/core/v1.0.0/rules/PI/pi-79@1.0.0.yaml +38 -0
  210. raxe/packs/core/v1.0.0/rules/PI/pi-80@1.0.0.yaml +38 -0
  211. raxe/packs/core/v1.0.0/rules/PI/pi-81@1.0.0.yaml +38 -0
  212. raxe/packs/core/v1.0.0/rules/PI/pi-82@1.0.0.yaml +38 -0
  213. raxe/packs/core/v1.0.0/rules/PI/pi-83@1.0.0.yaml +38 -0
  214. raxe/packs/core/v1.0.0/rules/PI/pi-84@1.0.0.yaml +38 -0
  215. raxe/packs/core/v1.0.0/rules/PI/pi-85@1.0.0.yaml +38 -0
  216. raxe/packs/core/v1.0.0/rules/PI/pi-86@1.0.0.yaml +38 -0
  217. raxe/packs/core/v1.0.0/rules/PI/pi-87@1.0.0.yaml +38 -0
  218. raxe/packs/core/v1.0.0/rules/PI/pi-88@1.0.0.yaml +38 -0
  219. raxe/packs/core/v1.0.0/rules/PI/pi-89@1.0.0.yaml +38 -0
  220. raxe/packs/core/v1.0.0/rules/PI/pi-90@1.0.0.yaml +38 -0
  221. raxe/packs/core/v1.0.0/rules/PI/pi-91@1.0.0.yaml +38 -0
  222. raxe/packs/core/v1.0.0/rules/PI/pi-92@1.0.0.yaml +38 -0
  223. raxe/packs/core/v1.0.0/rules/PI/pi-93@1.0.0.yaml +38 -0
  224. raxe/packs/core/v1.0.0/rules/PI/pi-94@1.0.0.yaml +38 -0
  225. raxe/packs/core/v1.0.0/rules/PI/pi-95@1.0.0.yaml +38 -0
  226. raxe/packs/core/v1.0.0/rules/PI/pi-96@1.0.0.yaml +38 -0
  227. raxe/packs/core/v1.0.0/rules/PI/pi-97@1.0.0.yaml +38 -0
  228. raxe/packs/core/v1.0.0/rules/PI/pi-98@1.0.0.yaml +38 -0
  229. raxe/packs/core/v1.0.0/rules/cmd/cmd-001@1.0.0.yaml +48 -0
  230. raxe/packs/core/v1.0.0/rules/cmd/cmd-007@1.0.0.yaml +48 -0
  231. raxe/packs/core/v1.0.0/rules/cmd/cmd-015@1.0.0.yaml +56 -0
  232. raxe/packs/core/v1.0.0/rules/cmd/cmd-016@1.0.0.yaml +46 -0
  233. raxe/packs/core/v1.0.0/rules/cmd/cmd-017@1.0.0.yaml +57 -0
  234. raxe/packs/core/v1.0.0/rules/cmd/cmd-021@1.0.0.yaml +46 -0
  235. raxe/packs/core/v1.0.0/rules/cmd/cmd-022@1.0.0.yaml +46 -0
  236. raxe/packs/core/v1.0.0/rules/cmd/cmd-023@1.0.0.yaml +78 -0
  237. raxe/packs/core/v1.0.0/rules/cmd/cmd-024@1.0.0.yaml +46 -0
  238. raxe/packs/core/v1.0.0/rules/cmd/cmd-025@1.0.0.yaml +93 -0
  239. raxe/packs/core/v1.0.0/rules/cmd/cmd-026@1.0.0.yaml +81 -0
  240. raxe/packs/core/v1.0.0/rules/cmd/cmd-027@1.0.0.yaml +82 -0
  241. raxe/packs/core/v1.0.0/rules/cmd/cmd-028@1.0.0.yaml +46 -0
  242. raxe/packs/core/v1.0.0/rules/cmd/cmd-033@1.0.0.yaml +48 -0
  243. raxe/packs/core/v1.0.0/rules/cmd/cmd-036@1.0.0.yaml +47 -0
  244. raxe/packs/core/v1.0.0/rules/cmd/cmd-037@1.0.0.yaml +44 -0
  245. raxe/packs/core/v1.0.0/rules/cmd/cmd-052@1.0.0.yaml +43 -0
  246. raxe/packs/core/v1.0.0/rules/cmd/cmd-054@1.0.0.yaml +44 -0
  247. raxe/packs/core/v1.0.0/rules/cmd/cmd-056@1.0.0.yaml +43 -0
  248. raxe/packs/core/v1.0.0/rules/cmd/cmd-065@1.0.0.yaml +46 -0
  249. raxe/packs/core/v1.0.0/rules/cmd/cmd-075@1.0.0.yaml +45 -0
  250. raxe/packs/core/v1.0.0/rules/cmd/cmd-079@1.0.0.yaml +44 -0
  251. raxe/packs/core/v1.0.0/rules/cmd/cmd-1080@1.0.0.yaml +41 -0
  252. raxe/packs/core/v1.0.0/rules/cmd/cmd-1090@1.0.0.yaml +41 -0
  253. raxe/packs/core/v1.0.0/rules/cmd/cmd-1104@1.0.0.yaml +44 -0
  254. raxe/packs/core/v1.0.0/rules/cmd/cmd-1105@1.0.0.yaml +41 -0
  255. raxe/packs/core/v1.0.0/rules/cmd/cmd-1112@1.0.0.yaml +44 -0
  256. raxe/packs/core/v1.0.0/rules/cmd/cmd-201@1.0.0.yaml +47 -0
  257. raxe/packs/core/v1.0.0/rules/cmd/cmd-202@1.0.0.yaml +42 -0
  258. raxe/packs/core/v1.0.0/rules/cmd/cmd-203@1.0.0.yaml +43 -0
  259. raxe/packs/core/v1.0.0/rules/cmd/cmd-204@1.0.0.yaml +47 -0
  260. raxe/packs/core/v1.0.0/rules/cmd/cmd-205@1.0.0.yaml +44 -0
  261. raxe/packs/core/v1.0.0/rules/cmd/cmd-206@1.0.0.yaml +47 -0
  262. raxe/packs/core/v1.0.0/rules/cmd/cmd-207@1.0.0.yaml +46 -0
  263. raxe/packs/core/v1.0.0/rules/cmd/cmd-208@1.0.0.yaml +42 -0
  264. raxe/packs/core/v1.0.0/rules/cmd/cmd-209@1.0.0.yaml +38 -0
  265. raxe/packs/core/v1.0.0/rules/cmd/cmd-210@1.0.0.yaml +38 -0
  266. raxe/packs/core/v1.0.0/rules/cmd/cmd-211@1.0.0.yaml +38 -0
  267. raxe/packs/core/v1.0.0/rules/cmd/cmd-212@1.0.0.yaml +38 -0
  268. raxe/packs/core/v1.0.0/rules/cmd/cmd-213@1.0.0.yaml +38 -0
  269. raxe/packs/core/v1.0.0/rules/cmd/cmd-214@1.0.0.yaml +38 -0
  270. raxe/packs/core/v1.0.0/rules/cmd/cmd-215@1.0.0.yaml +38 -0
  271. raxe/packs/core/v1.0.0/rules/cmd/cmd-216@1.0.0.yaml +38 -0
  272. raxe/packs/core/v1.0.0/rules/cmd/cmd-217@1.0.0.yaml +38 -0
  273. raxe/packs/core/v1.0.0/rules/cmd/cmd-218@1.0.0.yaml +38 -0
  274. raxe/packs/core/v1.0.0/rules/cmd/cmd-219@1.0.0.yaml +38 -0
  275. raxe/packs/core/v1.0.0/rules/cmd/cmd-220@1.0.0.yaml +38 -0
  276. raxe/packs/core/v1.0.0/rules/cmd/cmd-221@1.0.0.yaml +38 -0
  277. raxe/packs/core/v1.0.0/rules/cmd/cmd-222@1.0.0.yaml +38 -0
  278. raxe/packs/core/v1.0.0/rules/cmd/cmd-223@1.0.0.yaml +38 -0
  279. raxe/packs/core/v1.0.0/rules/cmd/cmd-224@1.0.0.yaml +38 -0
  280. raxe/packs/core/v1.0.0/rules/cmd/cmd-225@1.0.0.yaml +38 -0
  281. raxe/packs/core/v1.0.0/rules/cmd/cmd-226@1.0.0.yaml +38 -0
  282. raxe/packs/core/v1.0.0/rules/cmd/cmd-227@1.0.0.yaml +38 -0
  283. raxe/packs/core/v1.0.0/rules/cmd/cmd-228@1.0.0.yaml +38 -0
  284. raxe/packs/core/v1.0.0/rules/cmd/cmd-229@1.0.0.yaml +38 -0
  285. raxe/packs/core/v1.0.0/rules/cmd/cmd-230@1.0.0.yaml +38 -0
  286. raxe/packs/core/v1.0.0/rules/cmd/cmd-231@1.0.0.yaml +38 -0
  287. raxe/packs/core/v1.0.0/rules/cmd/cmd-232@1.0.0.yaml +38 -0
  288. raxe/packs/core/v1.0.0/rules/cmd/cmd-233@1.0.0.yaml +38 -0
  289. raxe/packs/core/v1.0.0/rules/cmd/cmd-234@1.0.0.yaml +38 -0
  290. raxe/packs/core/v1.0.0/rules/cmd/cmd-235@1.0.0.yaml +38 -0
  291. raxe/packs/core/v1.0.0/rules/cmd/cmd-236@1.0.0.yaml +38 -0
  292. raxe/packs/core/v1.0.0/rules/cmd/cmd-237@1.0.0.yaml +38 -0
  293. raxe/packs/core/v1.0.0/rules/cmd/cmd-238@1.0.0.yaml +38 -0
  294. raxe/packs/core/v1.0.0/rules/enc/enc-001@1.0.0.yaml +48 -0
  295. raxe/packs/core/v1.0.0/rules/enc/enc-013@1.0.0.yaml +46 -0
  296. raxe/packs/core/v1.0.0/rules/enc/enc-019@1.0.0.yaml +43 -0
  297. raxe/packs/core/v1.0.0/rules/enc/enc-020@1.0.0.yaml +47 -0
  298. raxe/packs/core/v1.0.0/rules/enc/enc-024@1.0.0.yaml +46 -0
  299. raxe/packs/core/v1.0.0/rules/enc/enc-029@1.0.0.yaml +44 -0
  300. raxe/packs/core/v1.0.0/rules/enc/enc-038@1.0.0.yaml +44 -0
  301. raxe/packs/core/v1.0.0/rules/enc/enc-044@1.0.0.yaml +46 -0
  302. raxe/packs/core/v1.0.0/rules/enc/enc-067@1.0.0.yaml +42 -0
  303. raxe/packs/core/v1.0.0/rules/enc/enc-069@1.0.0.yaml +42 -0
  304. raxe/packs/core/v1.0.0/rules/enc/enc-100@1.0.0.yaml +38 -0
  305. raxe/packs/core/v1.0.0/rules/enc/enc-101@1.0.0.yaml +38 -0
  306. raxe/packs/core/v1.0.0/rules/enc/enc-102@1.0.0.yaml +38 -0
  307. raxe/packs/core/v1.0.0/rules/enc/enc-103@1.0.0.yaml +38 -0
  308. raxe/packs/core/v1.0.0/rules/enc/enc-104@1.0.0.yaml +38 -0
  309. raxe/packs/core/v1.0.0/rules/enc/enc-105@1.0.0.yaml +38 -0
  310. raxe/packs/core/v1.0.0/rules/enc/enc-106@1.0.0.yaml +38 -0
  311. raxe/packs/core/v1.0.0/rules/enc/enc-107@1.0.0.yaml +38 -0
  312. raxe/packs/core/v1.0.0/rules/enc/enc-108@1.0.0.yaml +38 -0
  313. raxe/packs/core/v1.0.0/rules/enc/enc-109@1.0.0.yaml +38 -0
  314. raxe/packs/core/v1.0.0/rules/enc/enc-110@1.0.0.yaml +38 -0
  315. raxe/packs/core/v1.0.0/rules/enc/enc-111@1.0.0.yaml +38 -0
  316. raxe/packs/core/v1.0.0/rules/enc/enc-112@1.0.0.yaml +38 -0
  317. raxe/packs/core/v1.0.0/rules/enc/enc-113@1.0.0.yaml +38 -0
  318. raxe/packs/core/v1.0.0/rules/enc/enc-114@1.0.0.yaml +38 -0
  319. raxe/packs/core/v1.0.0/rules/enc/enc-115@1.0.0.yaml +38 -0
  320. raxe/packs/core/v1.0.0/rules/enc/enc-116@1.0.0.yaml +38 -0
  321. raxe/packs/core/v1.0.0/rules/enc/enc-117@1.0.0.yaml +38 -0
  322. raxe/packs/core/v1.0.0/rules/enc/enc-118@1.0.0.yaml +38 -0
  323. raxe/packs/core/v1.0.0/rules/enc/enc-119@1.0.0.yaml +38 -0
  324. raxe/packs/core/v1.0.0/rules/enc/enc-120@1.0.0.yaml +38 -0
  325. raxe/packs/core/v1.0.0/rules/enc/enc-201@1.0.0.yaml +37 -0
  326. raxe/packs/core/v1.0.0/rules/enc/enc-202@1.0.0.yaml +41 -0
  327. raxe/packs/core/v1.0.0/rules/enc/enc-203@1.0.0.yaml +41 -0
  328. raxe/packs/core/v1.0.0/rules/enc/enc-3004@1.0.0.yaml +40 -0
  329. raxe/packs/core/v1.0.0/rules/enc/enc-3006@1.0.0.yaml +40 -0
  330. raxe/packs/core/v1.0.0/rules/enc/enc-3011@1.0.0.yaml +40 -0
  331. raxe/packs/core/v1.0.0/rules/enc/enc-5016@1.0.0.yaml +46 -0
  332. raxe/packs/core/v1.0.0/rules/enc/enc-6001@1.0.0.yaml +53 -0
  333. raxe/packs/core/v1.0.0/rules/enc/enc-6002@1.0.0.yaml +41 -0
  334. raxe/packs/core/v1.0.0/rules/enc/enc-70@1.0.0.yaml +38 -0
  335. raxe/packs/core/v1.0.0/rules/enc/enc-71@1.0.0.yaml +38 -0
  336. raxe/packs/core/v1.0.0/rules/enc/enc-72@1.0.0.yaml +38 -0
  337. raxe/packs/core/v1.0.0/rules/enc/enc-73@1.0.0.yaml +38 -0
  338. raxe/packs/core/v1.0.0/rules/enc/enc-74@1.0.0.yaml +38 -0
  339. raxe/packs/core/v1.0.0/rules/enc/enc-75@1.0.0.yaml +38 -0
  340. raxe/packs/core/v1.0.0/rules/enc/enc-76@1.0.0.yaml +38 -0
  341. raxe/packs/core/v1.0.0/rules/enc/enc-77@1.0.0.yaml +38 -0
  342. raxe/packs/core/v1.0.0/rules/enc/enc-78@1.0.0.yaml +38 -0
  343. raxe/packs/core/v1.0.0/rules/enc/enc-79@1.0.0.yaml +38 -0
  344. raxe/packs/core/v1.0.0/rules/enc/enc-80@1.0.0.yaml +38 -0
  345. raxe/packs/core/v1.0.0/rules/enc/enc-81@1.0.0.yaml +38 -0
  346. raxe/packs/core/v1.0.0/rules/enc/enc-82@1.0.0.yaml +38 -0
  347. raxe/packs/core/v1.0.0/rules/enc/enc-83@1.0.0.yaml +38 -0
  348. raxe/packs/core/v1.0.0/rules/enc/enc-84@1.0.0.yaml +38 -0
  349. raxe/packs/core/v1.0.0/rules/enc/enc-85@1.0.0.yaml +38 -0
  350. raxe/packs/core/v1.0.0/rules/enc/enc-86@1.0.0.yaml +38 -0
  351. raxe/packs/core/v1.0.0/rules/enc/enc-87@1.0.0.yaml +38 -0
  352. raxe/packs/core/v1.0.0/rules/enc/enc-88@1.0.0.yaml +38 -0
  353. raxe/packs/core/v1.0.0/rules/enc/enc-89@1.0.0.yaml +38 -0
  354. raxe/packs/core/v1.0.0/rules/enc/enc-90@1.0.0.yaml +38 -0
  355. raxe/packs/core/v1.0.0/rules/enc/enc-91@1.0.0.yaml +38 -0
  356. raxe/packs/core/v1.0.0/rules/enc/enc-92@1.0.0.yaml +38 -0
  357. raxe/packs/core/v1.0.0/rules/enc/enc-93@1.0.0.yaml +38 -0
  358. raxe/packs/core/v1.0.0/rules/enc/enc-94@1.0.0.yaml +38 -0
  359. raxe/packs/core/v1.0.0/rules/enc/enc-95@1.0.0.yaml +38 -0
  360. raxe/packs/core/v1.0.0/rules/enc/enc-96@1.0.0.yaml +38 -0
  361. raxe/packs/core/v1.0.0/rules/enc/enc-97@1.0.0.yaml +38 -0
  362. raxe/packs/core/v1.0.0/rules/enc/enc-98@1.0.0.yaml +38 -0
  363. raxe/packs/core/v1.0.0/rules/enc/enc-99@1.0.0.yaml +38 -0
  364. raxe/packs/core/v1.0.0/rules/hc/hc-001@1.0.0.yaml +73 -0
  365. raxe/packs/core/v1.0.0/rules/hc/hc-002@1.0.0.yaml +71 -0
  366. raxe/packs/core/v1.0.0/rules/hc/hc-003@1.0.0.yaml +65 -0
  367. raxe/packs/core/v1.0.0/rules/hc/hc-004@1.0.0.yaml +73 -0
  368. raxe/packs/core/v1.0.0/rules/hc/hc-101@1.0.0.yaml +47 -0
  369. raxe/packs/core/v1.0.0/rules/hc/hc-102@1.0.0.yaml +47 -0
  370. raxe/packs/core/v1.0.0/rules/hc/hc-103@1.0.0.yaml +47 -0
  371. raxe/packs/core/v1.0.0/rules/hc/hc-104@1.0.0.yaml +47 -0
  372. raxe/packs/core/v1.0.0/rules/hc/hc-105@1.0.0.yaml +48 -0
  373. raxe/packs/core/v1.0.0/rules/hc/hc-106@1.0.0.yaml +40 -0
  374. raxe/packs/core/v1.0.0/rules/hc/hc-107@1.0.0.yaml +47 -0
  375. raxe/packs/core/v1.0.0/rules/hc/hc-108@1.0.0.yaml +47 -0
  376. raxe/packs/core/v1.0.0/rules/hc/hc-109@1.0.0.yaml +50 -0
  377. raxe/packs/core/v1.0.0/rules/hc/hc-110@1.0.0.yaml +56 -0
  378. raxe/packs/core/v1.0.0/rules/hc/hc-111@1.0.0.yaml +49 -0
  379. raxe/packs/core/v1.0.0/rules/hc/hc-112@1.0.0.yaml +53 -0
  380. raxe/packs/core/v1.0.0/rules/hc/hc-113@1.0.0.yaml +52 -0
  381. raxe/packs/core/v1.0.0/rules/hc/hc-114@1.0.0.yaml +52 -0
  382. raxe/packs/core/v1.0.0/rules/hc/hc-115@1.0.0.yaml +52 -0
  383. raxe/packs/core/v1.0.0/rules/hc/hc-116@1.0.0.yaml +53 -0
  384. raxe/packs/core/v1.0.0/rules/hc/hc-117@1.0.0.yaml +54 -0
  385. raxe/packs/core/v1.0.0/rules/hc/hc-118@1.0.0.yaml +52 -0
  386. raxe/packs/core/v1.0.0/rules/hc/hc-119@1.0.0.yaml +51 -0
  387. raxe/packs/core/v1.0.0/rules/hc/hc-120@1.0.0.yaml +52 -0
  388. raxe/packs/core/v1.0.0/rules/hc/hc-121@1.0.0.yaml +51 -0
  389. raxe/packs/core/v1.0.0/rules/hc/hc-122@1.0.0.yaml +51 -0
  390. raxe/packs/core/v1.0.0/rules/hc/hc-123@1.0.0.yaml +52 -0
  391. raxe/packs/core/v1.0.0/rules/hc/hc-124@1.0.0.yaml +53 -0
  392. raxe/packs/core/v1.0.0/rules/hc/hc-125@1.0.0.yaml +53 -0
  393. raxe/packs/core/v1.0.0/rules/hc/hc-126@1.0.0.yaml +53 -0
  394. raxe/packs/core/v1.0.0/rules/hc/hc-127@1.0.0.yaml +53 -0
  395. raxe/packs/core/v1.0.0/rules/hc/hc-128@1.0.0.yaml +53 -0
  396. raxe/packs/core/v1.0.0/rules/hc/hc-129@1.0.0.yaml +51 -0
  397. raxe/packs/core/v1.0.0/rules/hc/hc-130@1.0.0.yaml +51 -0
  398. raxe/packs/core/v1.0.0/rules/hc/hc-131@1.0.0.yaml +51 -0
  399. raxe/packs/core/v1.0.0/rules/hc/hc-132@1.0.0.yaml +51 -0
  400. raxe/packs/core/v1.0.0/rules/hc/hc-133@1.0.0.yaml +53 -0
  401. raxe/packs/core/v1.0.0/rules/hc/hc-134@1.0.0.yaml +51 -0
  402. raxe/packs/core/v1.0.0/rules/hc/hc-135@1.0.0.yaml +51 -0
  403. raxe/packs/core/v1.0.0/rules/hc/hc-136@1.0.0.yaml +51 -0
  404. raxe/packs/core/v1.0.0/rules/hc/hc-137@1.0.0.yaml +51 -0
  405. raxe/packs/core/v1.0.0/rules/hc/hc-138@1.0.0.yaml +51 -0
  406. raxe/packs/core/v1.0.0/rules/hc/hc-139@1.0.0.yaml +51 -0
  407. raxe/packs/core/v1.0.0/rules/hc/hc-140@1.0.0.yaml +51 -0
  408. raxe/packs/core/v1.0.0/rules/hc/hc-141@1.0.0.yaml +41 -0
  409. raxe/packs/core/v1.0.0/rules/hc/hc-142@1.0.0.yaml +37 -0
  410. raxe/packs/core/v1.0.0/rules/hc/hc-143@1.0.0.yaml +37 -0
  411. raxe/packs/core/v1.0.0/rules/hc/hc-144@1.0.0.yaml +37 -0
  412. raxe/packs/core/v1.0.0/rules/hc/hc-145@1.0.0.yaml +37 -0
  413. raxe/packs/core/v1.0.0/rules/hc/hc-146@1.0.0.yaml +37 -0
  414. raxe/packs/core/v1.0.0/rules/hc/hc-147@1.0.0.yaml +37 -0
  415. raxe/packs/core/v1.0.0/rules/hc/hc-148@1.0.0.yaml +37 -0
  416. raxe/packs/core/v1.0.0/rules/hc/hc-149@1.0.0.yaml +37 -0
  417. raxe/packs/core/v1.0.0/rules/hc/hc-150@1.0.0.yaml +37 -0
  418. raxe/packs/core/v1.0.0/rules/hc/hc-151@1.0.0.yaml +37 -0
  419. raxe/packs/core/v1.0.0/rules/hc/hc-152@1.0.0.yaml +37 -0
  420. raxe/packs/core/v1.0.0/rules/hc/hc-153@1.0.0.yaml +37 -0
  421. raxe/packs/core/v1.0.0/rules/hc/hc-154@1.0.0.yaml +37 -0
  422. raxe/packs/core/v1.0.0/rules/hc/hc-155@1.0.0.yaml +37 -0
  423. raxe/packs/core/v1.0.0/rules/hc/hc-156@1.0.0.yaml +37 -0
  424. raxe/packs/core/v1.0.0/rules/hc/hc-157@1.0.0.yaml +37 -0
  425. raxe/packs/core/v1.0.0/rules/hc/hc-158@1.0.0.yaml +37 -0
  426. raxe/packs/core/v1.0.0/rules/hc/hc-159@1.0.0.yaml +37 -0
  427. raxe/packs/core/v1.0.0/rules/hc/hc-160@1.0.0.yaml +37 -0
  428. raxe/packs/core/v1.0.0/rules/hc/hc-161@1.0.0.yaml +37 -0
  429. raxe/packs/core/v1.0.0/rules/jb/jb-001@1.0.0.yaml +47 -0
  430. raxe/packs/core/v1.0.0/rules/jb/jb-009@1.0.0.yaml +47 -0
  431. raxe/packs/core/v1.0.0/rules/jb/jb-020@1.0.0.yaml +47 -0
  432. raxe/packs/core/v1.0.0/rules/jb/jb-021@1.0.0.yaml +46 -0
  433. raxe/packs/core/v1.0.0/rules/jb/jb-022@1.0.0.yaml +47 -0
  434. raxe/packs/core/v1.0.0/rules/jb/jb-028@1.0.0.yaml +43 -0
  435. raxe/packs/core/v1.0.0/rules/jb/jb-033@1.0.0.yaml +46 -0
  436. raxe/packs/core/v1.0.0/rules/jb/jb-034@1.0.0.yaml +46 -0
  437. raxe/packs/core/v1.0.0/rules/jb/jb-036@1.0.0.yaml +41 -0
  438. raxe/packs/core/v1.0.0/rules/jb/jb-039@1.0.0.yaml +41 -0
  439. raxe/packs/core/v1.0.0/rules/jb/jb-056@1.0.0.yaml +38 -0
  440. raxe/packs/core/v1.0.0/rules/jb/jb-066@1.0.0.yaml +37 -0
  441. raxe/packs/core/v1.0.0/rules/jb/jb-076@1.0.0.yaml +37 -0
  442. raxe/packs/core/v1.0.0/rules/jb/jb-098@1.0.0.yaml +46 -0
  443. raxe/packs/core/v1.0.0/rules/jb/jb-103@1.0.0.yaml +47 -0
  444. raxe/packs/core/v1.0.0/rules/jb/jb-104@1.0.0.yaml +52 -0
  445. raxe/packs/core/v1.0.0/rules/jb/jb-105@1.0.0.yaml +56 -0
  446. raxe/packs/core/v1.0.0/rules/jb/jb-110@1.0.0.yaml +56 -0
  447. raxe/packs/core/v1.0.0/rules/jb/jb-111@1.0.0.yaml +57 -0
  448. raxe/packs/core/v1.0.0/rules/jb/jb-112@1.0.0.yaml +38 -0
  449. raxe/packs/core/v1.0.0/rules/jb/jb-113@1.0.0.yaml +38 -0
  450. raxe/packs/core/v1.0.0/rules/jb/jb-114@1.0.0.yaml +38 -0
  451. raxe/packs/core/v1.0.0/rules/jb/jb-115@1.0.0.yaml +38 -0
  452. raxe/packs/core/v1.0.0/rules/jb/jb-116@1.0.0.yaml +38 -0
  453. raxe/packs/core/v1.0.0/rules/jb/jb-117@1.0.0.yaml +38 -0
  454. raxe/packs/core/v1.0.0/rules/jb/jb-118@1.0.0.yaml +38 -0
  455. raxe/packs/core/v1.0.0/rules/jb/jb-119@1.0.0.yaml +38 -0
  456. raxe/packs/core/v1.0.0/rules/jb/jb-120@1.0.0.yaml +38 -0
  457. raxe/packs/core/v1.0.0/rules/jb/jb-121@1.0.0.yaml +38 -0
  458. raxe/packs/core/v1.0.0/rules/jb/jb-122@1.0.0.yaml +38 -0
  459. raxe/packs/core/v1.0.0/rules/jb/jb-123@1.0.0.yaml +38 -0
  460. raxe/packs/core/v1.0.0/rules/jb/jb-124@1.0.0.yaml +38 -0
  461. raxe/packs/core/v1.0.0/rules/jb/jb-125@1.0.0.yaml +38 -0
  462. raxe/packs/core/v1.0.0/rules/jb/jb-126@1.0.0.yaml +38 -0
  463. raxe/packs/core/v1.0.0/rules/jb/jb-127@1.0.0.yaml +38 -0
  464. raxe/packs/core/v1.0.0/rules/jb/jb-128@1.0.0.yaml +38 -0
  465. raxe/packs/core/v1.0.0/rules/jb/jb-129@1.0.0.yaml +38 -0
  466. raxe/packs/core/v1.0.0/rules/jb/jb-130@1.0.0.yaml +38 -0
  467. raxe/packs/core/v1.0.0/rules/jb/jb-131@1.0.0.yaml +38 -0
  468. raxe/packs/core/v1.0.0/rules/jb/jb-132@1.0.0.yaml +38 -0
  469. raxe/packs/core/v1.0.0/rules/jb/jb-133@1.0.0.yaml +38 -0
  470. raxe/packs/core/v1.0.0/rules/jb/jb-134@1.0.0.yaml +38 -0
  471. raxe/packs/core/v1.0.0/rules/jb/jb-135@1.0.0.yaml +38 -0
  472. raxe/packs/core/v1.0.0/rules/jb/jb-136@1.0.0.yaml +38 -0
  473. raxe/packs/core/v1.0.0/rules/jb/jb-137@1.0.0.yaml +38 -0
  474. raxe/packs/core/v1.0.0/rules/jb/jb-138@1.0.0.yaml +38 -0
  475. raxe/packs/core/v1.0.0/rules/jb/jb-139@1.0.0.yaml +38 -0
  476. raxe/packs/core/v1.0.0/rules/jb/jb-140@1.0.0.yaml +38 -0
  477. raxe/packs/core/v1.0.0/rules/jb/jb-141@1.0.0.yaml +38 -0
  478. raxe/packs/core/v1.0.0/rules/jb/jb-142@1.0.0.yaml +38 -0
  479. raxe/packs/core/v1.0.0/rules/jb/jb-143@1.0.0.yaml +38 -0
  480. raxe/packs/core/v1.0.0/rules/jb/jb-144@1.0.0.yaml +38 -0
  481. raxe/packs/core/v1.0.0/rules/jb/jb-145@1.0.0.yaml +38 -0
  482. raxe/packs/core/v1.0.0/rules/jb/jb-146@1.0.0.yaml +38 -0
  483. raxe/packs/core/v1.0.0/rules/jb/jb-147@1.0.0.yaml +38 -0
  484. raxe/packs/core/v1.0.0/rules/jb/jb-148@1.0.0.yaml +38 -0
  485. raxe/packs/core/v1.0.0/rules/jb/jb-149@1.0.0.yaml +38 -0
  486. raxe/packs/core/v1.0.0/rules/jb/jb-150@1.0.0.yaml +38 -0
  487. raxe/packs/core/v1.0.0/rules/jb/jb-151@1.0.0.yaml +38 -0
  488. raxe/packs/core/v1.0.0/rules/jb/jb-152@1.0.0.yaml +38 -0
  489. raxe/packs/core/v1.0.0/rules/jb/jb-153@1.0.0.yaml +38 -0
  490. raxe/packs/core/v1.0.0/rules/jb/jb-154@1.0.0.yaml +38 -0
  491. raxe/packs/core/v1.0.0/rules/jb/jb-155@1.0.0.yaml +38 -0
  492. raxe/packs/core/v1.0.0/rules/jb/jb-156@1.0.0.yaml +38 -0
  493. raxe/packs/core/v1.0.0/rules/jb/jb-157@1.0.0.yaml +38 -0
  494. raxe/packs/core/v1.0.0/rules/jb/jb-158@1.0.0.yaml +38 -0
  495. raxe/packs/core/v1.0.0/rules/jb/jb-159@1.0.0.yaml +38 -0
  496. raxe/packs/core/v1.0.0/rules/jb/jb-160@1.0.0.yaml +38 -0
  497. raxe/packs/core/v1.0.0/rules/jb/jb-161@1.0.0.yaml +38 -0
  498. raxe/packs/core/v1.0.0/rules/jb/jb-162@1.0.0.yaml +38 -0
  499. raxe/packs/core/v1.0.0/rules/jb/jb-201@1.0.0.yaml +40 -0
  500. raxe/packs/core/v1.0.0/rules/jb/jb-202@1.0.0.yaml +41 -0
  501. raxe/packs/core/v1.0.0/rules/jb/jb-203@1.0.0.yaml +51 -0
  502. raxe/packs/core/v1.0.0/rules/jb/jb-204@1.0.0.yaml +50 -0
  503. raxe/packs/core/v1.0.0/rules/jb/jb-205@1.0.0.yaml +50 -0
  504. raxe/packs/core/v1.0.0/rules/jb/jb-206@1.0.0.yaml +50 -0
  505. raxe/packs/core/v1.0.0/rules/jb/jb-207@1.0.0.yaml +49 -0
  506. raxe/packs/core/v1.0.0/rules/pii/pii-001@1.0.0.yaml +48 -0
  507. raxe/packs/core/v1.0.0/rules/pii/pii-009@1.0.0.yaml +48 -0
  508. raxe/packs/core/v1.0.0/rules/pii/pii-012@1.0.0.yaml +48 -0
  509. raxe/packs/core/v1.0.0/rules/pii/pii-017@1.0.0.yaml +48 -0
  510. raxe/packs/core/v1.0.0/rules/pii/pii-022@1.0.0.yaml +47 -0
  511. raxe/packs/core/v1.0.0/rules/pii/pii-025@1.0.0.yaml +47 -0
  512. raxe/packs/core/v1.0.0/rules/pii/pii-027@1.0.0.yaml +47 -0
  513. raxe/packs/core/v1.0.0/rules/pii/pii-028@1.0.0.yaml +47 -0
  514. raxe/packs/core/v1.0.0/rules/pii/pii-034@1.0.0.yaml +47 -0
  515. raxe/packs/core/v1.0.0/rules/pii/pii-037@1.0.0.yaml +47 -0
  516. raxe/packs/core/v1.0.0/rules/pii/pii-040@1.0.0.yaml +47 -0
  517. raxe/packs/core/v1.0.0/rules/pii/pii-041@1.0.0.yaml +47 -0
  518. raxe/packs/core/v1.0.0/rules/pii/pii-044@1.0.0.yaml +47 -0
  519. raxe/packs/core/v1.0.0/rules/pii/pii-050@1.0.0.yaml +57 -0
  520. raxe/packs/core/v1.0.0/rules/pii/pii-051@1.0.0.yaml +53 -0
  521. raxe/packs/core/v1.0.0/rules/pii/pii-052@1.0.0.yaml +52 -0
  522. raxe/packs/core/v1.0.0/rules/pii/pii-053@1.0.0.yaml +56 -0
  523. raxe/packs/core/v1.0.0/rules/pii/pii-054@1.0.0.yaml +53 -0
  524. raxe/packs/core/v1.0.0/rules/pii/pii-055@1.0.0.yaml +51 -0
  525. raxe/packs/core/v1.0.0/rules/pii/pii-056@1.0.0.yaml +51 -0
  526. raxe/packs/core/v1.0.0/rules/pii/pii-058@1.0.0.yaml +47 -0
  527. raxe/packs/core/v1.0.0/rules/pii/pii-2015@1.0.0.yaml +41 -0
  528. raxe/packs/core/v1.0.0/rules/pii/pii-2025@1.0.0.yaml +35 -0
  529. raxe/packs/core/v1.0.0/rules/pii/pii-2026@1.0.0.yaml +39 -0
  530. raxe/packs/core/v1.0.0/rules/pii/pii-2035@1.0.0.yaml +39 -0
  531. raxe/packs/core/v1.0.0/rules/pii/pii-2037@1.0.0.yaml +39 -0
  532. raxe/packs/core/v1.0.0/rules/pii/pii-2042@1.0.0.yaml +39 -0
  533. raxe/packs/core/v1.0.0/rules/pii/pii-3001@1.0.0.yaml +39 -0
  534. raxe/packs/core/v1.0.0/rules/pii/pii-3002@1.0.0.yaml +41 -0
  535. raxe/packs/core/v1.0.0/rules/pii/pii-3003@1.0.0.yaml +36 -0
  536. raxe/packs/core/v1.0.0/rules/pii/pii-3004@1.0.0.yaml +41 -0
  537. raxe/packs/core/v1.0.0/rules/pii/pii-3005@1.0.0.yaml +39 -0
  538. raxe/packs/core/v1.0.0/rules/pii/pii-3006@1.0.0.yaml +35 -0
  539. raxe/packs/core/v1.0.0/rules/pii/pii-3007@1.0.0.yaml +37 -0
  540. raxe/packs/core/v1.0.0/rules/pii/pii-3008@1.0.0.yaml +35 -0
  541. raxe/packs/core/v1.0.0/rules/pii/pii-3009@1.0.0.yaml +42 -0
  542. raxe/packs/core/v1.0.0/rules/pii/pii-3010@1.0.0.yaml +39 -0
  543. raxe/packs/core/v1.0.0/rules/pii/pii-3011@1.0.0.yaml +35 -0
  544. raxe/packs/core/v1.0.0/rules/pii/pii-3012@1.0.0.yaml +35 -0
  545. raxe/packs/core/v1.0.0/rules/pii/pii-3013@1.0.0.yaml +36 -0
  546. raxe/packs/core/v1.0.0/rules/pii/pii-3014@1.0.0.yaml +36 -0
  547. raxe/packs/core/v1.0.0/rules/pii/pii-3015@1.0.0.yaml +42 -0
  548. raxe/packs/core/v1.0.0/rules/pii/pii-3016@1.0.0.yaml +42 -0
  549. raxe/packs/core/v1.0.0/rules/pii/pii-3017@1.0.0.yaml +40 -0
  550. raxe/packs/core/v1.0.0/rules/pii/pii-3018@1.0.0.yaml +38 -0
  551. raxe/packs/core/v1.0.0/rules/pii/pii-3019@1.0.0.yaml +40 -0
  552. raxe/packs/core/v1.0.0/rules/pii/pii-3020@1.0.0.yaml +40 -0
  553. raxe/packs/core/v1.0.0/rules/pii/pii-3021@1.0.0.yaml +39 -0
  554. raxe/packs/core/v1.0.0/rules/pii/pii-3022@1.0.0.yaml +36 -0
  555. raxe/packs/core/v1.0.0/rules/pii/pii-3023@1.0.0.yaml +41 -0
  556. raxe/packs/core/v1.0.0/rules/pii/pii-3024@1.0.0.yaml +37 -0
  557. raxe/packs/core/v1.0.0/rules/pii/pii-3025@1.0.0.yaml +38 -0
  558. raxe/packs/core/v1.0.0/rules/pii/pii-3026@1.0.0.yaml +42 -0
  559. raxe/packs/core/v1.0.0/rules/pii/pii-3027@1.0.0.yaml +38 -0
  560. raxe/packs/core/v1.0.0/rules/pii/pii-3028@1.0.0.yaml +42 -0
  561. raxe/packs/core/v1.0.0/rules/pii/pii-3029@1.0.0.yaml +36 -0
  562. raxe/packs/core/v1.0.0/rules/pii/pii-3030@1.0.0.yaml +42 -0
  563. raxe/packs/core/v1.0.0/rules/pii/pii-3031@1.0.0.yaml +37 -0
  564. raxe/packs/core/v1.0.0/rules/pii/pii-3032@1.0.0.yaml +42 -0
  565. raxe/packs/core/v1.0.0/rules/pii/pii-3033@1.0.0.yaml +39 -0
  566. raxe/packs/core/v1.0.0/rules/pii/pii-3034@1.0.0.yaml +40 -0
  567. raxe/packs/core/v1.0.0/rules/pii/pii-3035@1.0.0.yaml +43 -0
  568. raxe/packs/core/v1.0.0/rules/pii/pii-3036@1.0.0.yaml +41 -0
  569. raxe/packs/core/v1.0.0/rules/pii/pii-3037@1.0.0.yaml +35 -0
  570. raxe/packs/core/v1.0.0/rules/pii/pii-3038@1.0.0.yaml +35 -0
  571. raxe/packs/core/v1.0.0/rules/pii/pii-3039@1.0.0.yaml +35 -0
  572. raxe/packs/core/v1.0.0/rules/pii/pii-3040@1.0.0.yaml +41 -0
  573. raxe/packs/core/v1.0.0/rules/pii/pii-3041@1.0.0.yaml +39 -0
  574. raxe/packs/core/v1.0.0/rules/pii/pii-3042@1.0.0.yaml +36 -0
  575. raxe/packs/core/v1.0.0/rules/pii/pii-3043@1.0.0.yaml +35 -0
  576. raxe/packs/core/v1.0.0/rules/pii/pii-3044@1.0.0.yaml +43 -0
  577. raxe/packs/core/v1.0.0/rules/pii/pii-3045@1.0.0.yaml +36 -0
  578. raxe/packs/core/v1.0.0/rules/pii/pii-3046@1.0.0.yaml +37 -0
  579. raxe/packs/core/v1.0.0/rules/pii/pii-3047@1.0.0.yaml +36 -0
  580. raxe/packs/core/v1.0.0/rules/pii/pii-3048@1.0.0.yaml +36 -0
  581. raxe/packs/core/v1.0.0/rules/pii/pii-3049@1.0.0.yaml +38 -0
  582. raxe/packs/core/v1.0.0/rules/pii/pii-3050@1.0.0.yaml +44 -0
  583. raxe/packs/core/v1.0.0/rules/pii/pii-3051@1.0.0.yaml +35 -0
  584. raxe/packs/core/v1.0.0/rules/pii/pii-3052@1.0.0.yaml +36 -0
  585. raxe/packs/core/v1.0.0/rules/pii/pii-3053@1.0.0.yaml +35 -0
  586. raxe/packs/core/v1.0.0/rules/pii/pii-3054@1.0.0.yaml +35 -0
  587. raxe/packs/core/v1.0.0/rules/pii/pii-3055@1.0.0.yaml +40 -0
  588. raxe/packs/core/v1.0.0/rules/pii/pii-3056@1.0.0.yaml +38 -0
  589. raxe/packs/core/v1.0.0/rules/pii/pii-3057@1.0.0.yaml +40 -0
  590. raxe/packs/core/v1.0.0/rules/pii/pii-3058@1.0.0.yaml +43 -0
  591. raxe/packs/core/v1.0.0/rules/pii/pii-3059@1.0.0.yaml +42 -0
  592. raxe/packs/core/v1.0.0/rules/pii/pii-3060@1.0.0.yaml +42 -0
  593. raxe/packs/core/v1.0.0/rules/pii/pii-3061@1.0.0.yaml +50 -0
  594. raxe/packs/core/v1.0.0/rules/pii/pii-3062@1.0.0.yaml +50 -0
  595. raxe/packs/core/v1.0.0/rules/pii/pii-3063@1.0.0.yaml +54 -0
  596. raxe/packs/core/v1.0.0/rules/pii/pii-3064@1.0.0.yaml +78 -0
  597. raxe/packs/core/v1.0.0/rules/pii/pii-3065@1.0.0.yaml +84 -0
  598. raxe/packs/core/v1.0.0/rules/pii/pii-3066@1.0.0.yaml +84 -0
  599. raxe/packs/core/v1.0.0/rules/pii/pii-3067@1.0.0.yaml +88 -0
  600. raxe/packs/core/v1.0.0/rules/pii/pii-3068@1.0.0.yaml +94 -0
  601. raxe/packs/core/v1.0.0/rules/pii/pii-3069@1.0.0.yaml +90 -0
  602. raxe/packs/core/v1.0.0/rules/pii/pii-3070@1.0.0.yaml +99 -0
  603. raxe/packs/core/v1.0.0/rules/pii/pii-3071@1.0.0.yaml +91 -0
  604. raxe/packs/core/v1.0.0/rules/pii/pii-3072@1.0.0.yaml +38 -0
  605. raxe/packs/core/v1.0.0/rules/pii/pii-3073@1.0.0.yaml +38 -0
  606. raxe/packs/core/v1.0.0/rules/pii/pii-3074@1.0.0.yaml +38 -0
  607. raxe/packs/core/v1.0.0/rules/pii/pii-3075@1.0.0.yaml +38 -0
  608. raxe/packs/core/v1.0.0/rules/pii/pii-3076@1.0.0.yaml +38 -0
  609. raxe/packs/core/v1.0.0/rules/pii/pii-3077@1.0.0.yaml +38 -0
  610. raxe/packs/core/v1.0.0/rules/pii/pii-3078@1.0.0.yaml +38 -0
  611. raxe/packs/core/v1.0.0/rules/pii/pii-3079@1.0.0.yaml +38 -0
  612. raxe/packs/core/v1.0.0/rules/pii/pii-3080@1.0.0.yaml +38 -0
  613. raxe/packs/core/v1.0.0/rules/pii/pii-3081@1.0.0.yaml +38 -0
  614. raxe/packs/core/v1.0.0/rules/pii/pii-3082@1.0.0.yaml +38 -0
  615. raxe/packs/core/v1.0.0/rules/pii/pii-3083@1.0.0.yaml +38 -0
  616. raxe/packs/core/v1.0.0/rules/pii/pii-3084@1.0.0.yaml +38 -0
  617. raxe/packs/core/v1.0.0/rules/pii/pii-3085@1.0.0.yaml +38 -0
  618. raxe/packs/core/v1.0.0/rules/rag/rag-016@1.0.0.yaml +47 -0
  619. raxe/packs/core/v1.0.0/rules/rag/rag-028@1.0.0.yaml +47 -0
  620. raxe/packs/core/v1.0.0/rules/rag/rag-042@1.0.0.yaml +47 -0
  621. raxe/packs/core/v1.0.0/rules/rag/rag-044@1.0.0.yaml +47 -0
  622. raxe/packs/core/v1.0.0/rules/rag/rag-045@1.0.0.yaml +47 -0
  623. raxe/packs/core/v1.0.0/rules/rag/rag-050@1.0.0.yaml +47 -0
  624. raxe/packs/core/v1.0.0/rules/rag/rag-201@1.0.0.yaml +41 -0
  625. raxe/packs/core/v1.0.0/rules/rag/rag-202@1.0.0.yaml +41 -0
  626. raxe/packs/core/v1.0.0/rules/rag/rag-3001@1.0.0.yaml +41 -0
  627. raxe/packs/core/v1.0.0/rules/rag/rag-3006@1.0.0.yaml +41 -0
  628. raxe/packs/core/v1.0.0/rules/rag/rag-3009@1.0.0.yaml +41 -0
  629. raxe/packs/core/v1.0.0/rules/rag/rag-3012@1.0.0.yaml +41 -0
  630. raxe/plugins/__init__.py +98 -0
  631. raxe/plugins/custom_rules.py +380 -0
  632. raxe/plugins/loader.py +389 -0
  633. raxe/plugins/manager.py +538 -0
  634. raxe/plugins/protocol.py +428 -0
  635. raxe/py.typed +0 -0
  636. raxe/sdk/__init__.py +77 -0
  637. raxe/sdk/agent_scanner.py +1918 -0
  638. raxe/sdk/client.py +1603 -0
  639. raxe/sdk/decorator.py +175 -0
  640. raxe/sdk/exceptions.py +859 -0
  641. raxe/sdk/integrations/__init__.py +277 -0
  642. raxe/sdk/integrations/agent_scanner.py +71 -0
  643. raxe/sdk/integrations/autogen.py +872 -0
  644. raxe/sdk/integrations/crewai.py +1368 -0
  645. raxe/sdk/integrations/dspy.py +845 -0
  646. raxe/sdk/integrations/extractors.py +363 -0
  647. raxe/sdk/integrations/huggingface.py +395 -0
  648. raxe/sdk/integrations/langchain.py +948 -0
  649. raxe/sdk/integrations/litellm.py +484 -0
  650. raxe/sdk/integrations/llamaindex.py +1049 -0
  651. raxe/sdk/integrations/portkey.py +831 -0
  652. raxe/sdk/suppression_context.py +215 -0
  653. raxe/sdk/wrappers/__init__.py +163 -0
  654. raxe/sdk/wrappers/anthropic.py +310 -0
  655. raxe/sdk/wrappers/openai.py +221 -0
  656. raxe/sdk/wrappers/vertexai.py +484 -0
  657. raxe/utils/__init__.py +12 -0
  658. raxe/utils/error_sanitizer.py +135 -0
  659. raxe/utils/logging.py +241 -0
  660. raxe/utils/performance.py +414 -0
  661. raxe/utils/profiler.py +339 -0
  662. raxe/utils/validators.py +170 -0
  663. raxe-0.4.6.dist-info/METADATA +471 -0
  664. raxe-0.4.6.dist-info/RECORD +668 -0
  665. raxe-0.4.6.dist-info/WHEEL +5 -0
  666. raxe-0.4.6.dist-info/entry_points.txt +2 -0
  667. raxe-0.4.6.dist-info/licenses/LICENSE +56 -0
  668. raxe-0.4.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1282 @@
1
+ """
2
+ Telemetry event factory module with all 12 event types.
3
+
4
+ This module contains ONLY pure functions - no I/O operations.
5
+ All functions take data and return data without side effects.
6
+
7
+ Event Types:
8
+ - installation: Fired once on first import/install
9
+ - activation: Tracks first use of specific features
10
+ - session_start: Fired when Python interpreter session begins
11
+ - session_end: Fired when session ends
12
+ - scan: Core telemetry event for each threat detection scan
13
+ - error: Fired when an error occurs
14
+ - performance: Aggregated performance metrics
15
+ - feature_usage: Tracks usage of specific features
16
+ - heartbeat: Periodic health signal
17
+ - key_upgrade: Fired when API key is upgraded
18
+ - config_changed: Fired when configuration is changed
19
+ - team_invite: Tracks team invitations for viral growth metrics
20
+
21
+ Priority Assignment:
22
+ - Critical: installation, activation, session_end, error, key_upgrade, team_invite
23
+ - Standard: session_start, performance, feature_usage, heartbeat
24
+ - Conditional: scan (critical if threat HIGH+), config_changed (critical if disabling telemetry)
25
+ """
26
+
27
+ from dataclasses import dataclass
28
+ from datetime import datetime, timezone
29
+ from enum import Enum
30
+ from typing import Any, Literal
31
+ from uuid import uuid4
32
+
33
+ from .event_creator import hash_text
34
+
35
+
36
+ class EventType(str, Enum):
37
+ """Enumeration of all telemetry event types."""
38
+
39
+ INSTALLATION = "installation"
40
+ ACTIVATION = "activation"
41
+ SESSION_START = "session_start"
42
+ SESSION_END = "session_end"
43
+ SCAN = "scan"
44
+ ERROR = "error"
45
+ PERFORMANCE = "performance"
46
+ FEATURE_USAGE = "feature_usage"
47
+ HEARTBEAT = "heartbeat"
48
+ KEY_UPGRADE = "key_upgrade"
49
+ CONFIG_CHANGED = "config_changed"
50
+ TEAM_INVITE = "team_invite"
51
+
52
+
53
+ @dataclass(frozen=True)
54
+ class TelemetryEvent:
55
+ """Immutable telemetry event container.
56
+
57
+ Attributes:
58
+ event_id: Unique event identifier with evt_ prefix.
59
+ event_type: Type of event from EventType enum.
60
+ timestamp: ISO 8601 UTC timestamp of event creation.
61
+ priority: Event priority level (critical or standard).
62
+ payload: Event-specific data dictionary.
63
+ org_id: Organization ID for multi-tenant tracking (optional).
64
+ team_id: Team ID for team-level analytics (optional).
65
+ """
66
+
67
+ event_id: str
68
+ event_type: str
69
+ timestamp: str
70
+ priority: Literal["critical", "standard"]
71
+ payload: dict[str, Any]
72
+ org_id: str | None = None
73
+ team_id: str | None = None
74
+
75
+
76
+ # =============================================================================
77
+ # ID Generators
78
+ # =============================================================================
79
+
80
+
81
+ def generate_event_id() -> str:
82
+ """Generate a unique event identifier.
83
+
84
+ Returns:
85
+ Event ID with evt_ prefix followed by 16 hex characters.
86
+
87
+ Example:
88
+ >>> generate_event_id()
89
+ 'evt_a1b2c3d4e5f67890'
90
+ """
91
+ return f"evt_{uuid4().hex[:16]}"
92
+
93
+
94
+ def generate_installation_id() -> str:
95
+ """Generate a unique installation identifier.
96
+
97
+ Returns:
98
+ Installation ID with inst_ prefix followed by 16 hex characters.
99
+
100
+ Example:
101
+ >>> generate_installation_id()
102
+ 'inst_a1b2c3d4e5f67890'
103
+ """
104
+ return f"inst_{uuid4().hex[:16]}"
105
+
106
+
107
+ def generate_session_id() -> str:
108
+ """Generate a unique session identifier.
109
+
110
+ Returns:
111
+ Session ID with sess_ prefix followed by 16 hex characters.
112
+
113
+ Example:
114
+ >>> generate_session_id()
115
+ 'sess_a1b2c3d4e5f67890'
116
+ """
117
+ return f"sess_{uuid4().hex[:16]}"
118
+
119
+
120
+ def generate_batch_id() -> str:
121
+ """Generate a unique batch identifier.
122
+
123
+ Returns:
124
+ Batch ID with batch_ prefix followed by 16 hex characters.
125
+
126
+ Example:
127
+ >>> generate_batch_id()
128
+ 'batch_a1b2c3d4e5f67890'
129
+ """
130
+ return f"batch_{uuid4().hex[:16]}"
131
+
132
+
133
+ def _get_utc_timestamp() -> str:
134
+ """Get current UTC timestamp in ISO 8601 format.
135
+
136
+ Returns:
137
+ ISO 8601 formatted UTC timestamp string.
138
+ """
139
+ return datetime.now(timezone.utc).isoformat()
140
+
141
+
142
+ # =============================================================================
143
+ # Installation Event
144
+ # =============================================================================
145
+
146
+
147
+ def create_installation_event(
148
+ installation_id: str,
149
+ client_version: str,
150
+ python_version: str,
151
+ platform: Literal["darwin", "linux", "win32"],
152
+ install_method: Literal["pip", "uv", "pipx", "poetry", "conda", "source", "docker", "unknown"],
153
+ *,
154
+ key_type: Literal["temp", "community", "pro", "enterprise"] = "temp",
155
+ ml_available: bool | None = None,
156
+ installed_extras: list[str] | None = None,
157
+ platform_version: str | None = None,
158
+ acquisition_source: Literal[
159
+ "pip_install",
160
+ "github_release",
161
+ "docker",
162
+ "homebrew",
163
+ "website_download",
164
+ "referral",
165
+ "enterprise_deploy",
166
+ "ci_integration",
167
+ "unknown",
168
+ ] = "unknown",
169
+ org_id: str | None = None,
170
+ team_id: str | None = None,
171
+ ) -> TelemetryEvent:
172
+ """Create an installation telemetry event.
173
+
174
+ Fired once on first import/install of RAXE.
175
+
176
+ Args:
177
+ installation_id: Unique installation identifier (inst_ prefix).
178
+ client_version: RAXE version installed.
179
+ python_version: Python interpreter version.
180
+ platform: Operating system platform.
181
+ install_method: Package manager used for installation.
182
+ key_type: API key tier at installation time.
183
+ - temp: Temporary key (auto-generated, 14-day expiry)
184
+ - community: Free registered user
185
+ - pro: Paid individual user
186
+ - enterprise: Team/organization plan
187
+ ml_available: Whether ML dependencies are installed.
188
+ installed_extras: List of installed optional extras.
189
+ platform_version: OS version string.
190
+ acquisition_source: How the user discovered/acquired RAXE.
191
+ - pip_install: Installed via pip install raxe
192
+ - github_release: Downloaded from GitHub releases
193
+ - docker: Installed via Docker image
194
+ - homebrew: Installed via brew install raxe
195
+ - website_download: Downloaded from raxe.ai
196
+ - referral: Referred by another user (via RAXE_REFERRAL_CODE)
197
+ - enterprise_deploy: Enterprise deployment
198
+ - ci_integration: Installed in CI/CD pipeline
199
+ - unknown: Default/fallback
200
+ org_id: Organization ID for multi-tenant tracking.
201
+ team_id: Team ID for team-level analytics.
202
+
203
+ Returns:
204
+ TelemetryEvent with installation payload.
205
+
206
+ Example:
207
+ >>> event = create_installation_event(
208
+ ... installation_id="inst_abc123",
209
+ ... client_version="0.0.1",
210
+ ... python_version="3.11.5",
211
+ ... platform="darwin",
212
+ ... install_method="pip",
213
+ ... ml_available=True,
214
+ ... installed_extras=["ml", "openai"],
215
+ ... acquisition_source="pip_install",
216
+ ... org_id="org_123",
217
+ ... team_id="team_456",
218
+ ... )
219
+ """
220
+ payload: dict[str, Any] = {
221
+ "installation_id": installation_id,
222
+ "client_version": client_version,
223
+ "python_version": python_version,
224
+ "platform": platform,
225
+ "install_method": install_method,
226
+ "key_type": key_type,
227
+ "acquisition_source": acquisition_source,
228
+ }
229
+
230
+ if ml_available is not None:
231
+ payload["ml_available"] = ml_available
232
+
233
+ if installed_extras is not None:
234
+ payload["installed_extras"] = installed_extras
235
+
236
+ if platform_version is not None:
237
+ payload["platform_version"] = platform_version
238
+
239
+ return TelemetryEvent(
240
+ event_id=generate_event_id(),
241
+ event_type=EventType.INSTALLATION.value,
242
+ timestamp=_get_utc_timestamp(),
243
+ priority="critical",
244
+ payload=payload,
245
+ org_id=org_id,
246
+ team_id=team_id,
247
+ )
248
+
249
+
250
+ # =============================================================================
251
+ # Activation Event
252
+ # =============================================================================
253
+
254
+
255
+ def create_activation_event(
256
+ feature: Literal[
257
+ "first_scan",
258
+ "first_threat",
259
+ "first_block",
260
+ "first_cli",
261
+ "first_sdk",
262
+ "first_decorator",
263
+ "first_wrapper",
264
+ "first_langchain",
265
+ "first_l2_detection",
266
+ "first_custom_rule",
267
+ ],
268
+ seconds_since_install: float,
269
+ *,
270
+ activation_context: dict[str, Any] | None = None,
271
+ org_id: str | None = None,
272
+ team_id: str | None = None,
273
+ ) -> TelemetryEvent:
274
+ """Create an activation telemetry event.
275
+
276
+ Tracks first use of specific features (time-to-value metrics).
277
+
278
+ Args:
279
+ feature: Feature being activated for the first time.
280
+ Canonical values aligned with backend:
281
+ - first_scan: First prompt scan performed
282
+ - first_threat: First threat detected
283
+ - first_block: First threat blocked by policy
284
+ - first_cli: First CLI command executed
285
+ - first_sdk: First SDK API call
286
+ - first_decorator: First use of @protect decorator
287
+ - first_wrapper: First use of OpenAI/Anthropic wrapper
288
+ - first_langchain: First LangChain integration use
289
+ - first_l2_detection: First ML-based (L2) detection
290
+ - first_custom_rule: First custom rule loaded
291
+ seconds_since_install: Time elapsed since installation event.
292
+ activation_context: Additional context about the activation.
293
+ org_id: Organization ID for multi-tenant tracking.
294
+ team_id: Team ID for team-level analytics.
295
+
296
+ Returns:
297
+ TelemetryEvent with activation payload.
298
+
299
+ Example:
300
+ >>> event = create_activation_event(
301
+ ... feature="first_scan",
302
+ ... seconds_since_install=120.5,
303
+ ... activation_context={"entry_point": "cli"},
304
+ ... org_id="org_123",
305
+ ... team_id="team_456",
306
+ ... )
307
+ """
308
+ payload: dict[str, Any] = {
309
+ "feature": feature,
310
+ "seconds_since_install": seconds_since_install,
311
+ }
312
+
313
+ if activation_context is not None:
314
+ payload["activation_context"] = activation_context
315
+
316
+ return TelemetryEvent(
317
+ event_id=generate_event_id(),
318
+ event_type=EventType.ACTIVATION.value,
319
+ timestamp=_get_utc_timestamp(),
320
+ priority="critical",
321
+ payload=payload,
322
+ org_id=org_id,
323
+ team_id=team_id,
324
+ )
325
+
326
+
327
+ # =============================================================================
328
+ # Session Start Event
329
+ # =============================================================================
330
+
331
+
332
+ def create_session_start_event(
333
+ session_id: str,
334
+ session_number: int,
335
+ *,
336
+ entry_point: Literal["cli", "sdk", "wrapper", "integration", "repl"] | None = None,
337
+ previous_session_gap_hours: float | None = None,
338
+ environment: dict[str, bool] | None = None,
339
+ org_id: str | None = None,
340
+ team_id: str | None = None,
341
+ ) -> TelemetryEvent:
342
+ """Create a session start telemetry event.
343
+
344
+ Fired when a new Python interpreter session begins (DAU/WAU/MAU tracking).
345
+
346
+ Args:
347
+ session_id: Unique session identifier (sess_ prefix).
348
+ session_number: Sequential session count for this installation.
349
+ entry_point: How RAXE was invoked.
350
+ previous_session_gap_hours: Hours since last session ended.
351
+ environment: Session environment details (is_ci, is_interactive, is_notebook).
352
+ org_id: Organization ID for multi-tenant tracking.
353
+ team_id: Team ID for team-level analytics.
354
+
355
+ Returns:
356
+ TelemetryEvent with session_start payload.
357
+
358
+ Example:
359
+ >>> event = create_session_start_event(
360
+ ... session_id="sess_abc123",
361
+ ... session_number=5,
362
+ ... entry_point="cli",
363
+ ... previous_session_gap_hours=24.5,
364
+ ... environment={"is_ci": False, "is_interactive": True},
365
+ ... org_id="org_123",
366
+ ... team_id="team_456",
367
+ ... )
368
+ """
369
+ payload: dict[str, Any] = {
370
+ "session_id": session_id,
371
+ "session_number": session_number,
372
+ }
373
+
374
+ if entry_point is not None:
375
+ payload["entry_point"] = entry_point
376
+
377
+ if previous_session_gap_hours is not None:
378
+ payload["previous_session_gap_hours"] = previous_session_gap_hours
379
+
380
+ if environment is not None:
381
+ payload["environment"] = environment
382
+
383
+ return TelemetryEvent(
384
+ event_id=generate_event_id(),
385
+ event_type=EventType.SESSION_START.value,
386
+ timestamp=_get_utc_timestamp(),
387
+ priority="standard",
388
+ payload=payload,
389
+ org_id=org_id,
390
+ team_id=team_id,
391
+ )
392
+
393
+
394
+ # =============================================================================
395
+ # Session End Event
396
+ # =============================================================================
397
+
398
+
399
+ def create_session_end_event(
400
+ session_id: str,
401
+ duration_seconds: float,
402
+ scans_in_session: int,
403
+ threats_in_session: int,
404
+ *,
405
+ end_reason: Literal["normal", "error", "timeout", "interrupt", "unknown"] | None = None,
406
+ peak_memory_mb: float | None = None,
407
+ features_used: list[str] | None = None,
408
+ org_id: str | None = None,
409
+ team_id: str | None = None,
410
+ ) -> TelemetryEvent:
411
+ """Create a session end telemetry event.
412
+
413
+ Fired when Python interpreter session ends (engagement metrics).
414
+
415
+ Args:
416
+ session_id: Session being ended (sess_ prefix).
417
+ duration_seconds: Total session duration.
418
+ scans_in_session: Number of scans performed.
419
+ threats_in_session: Number of threats detected.
420
+ end_reason: How session ended.
421
+ peak_memory_mb: Peak memory usage during session.
422
+ features_used: Features used during session.
423
+ org_id: Organization ID for multi-tenant tracking.
424
+ team_id: Team ID for team-level analytics.
425
+
426
+ Returns:
427
+ TelemetryEvent with session_end payload.
428
+
429
+ Example:
430
+ >>> event = create_session_end_event(
431
+ ... session_id="sess_abc123",
432
+ ... duration_seconds=3600.0,
433
+ ... scans_in_session=50,
434
+ ... threats_in_session=3,
435
+ ... end_reason="normal",
436
+ ... peak_memory_mb=150.5,
437
+ ... features_used=["cli", "explain"],
438
+ ... org_id="org_123",
439
+ ... team_id="team_456",
440
+ ... )
441
+ """
442
+ payload: dict[str, Any] = {
443
+ "session_id": session_id,
444
+ "duration_seconds": duration_seconds,
445
+ "scans_in_session": scans_in_session,
446
+ "threats_in_session": threats_in_session,
447
+ }
448
+
449
+ if end_reason is not None:
450
+ payload["end_reason"] = end_reason
451
+
452
+ if peak_memory_mb is not None:
453
+ payload["peak_memory_mb"] = peak_memory_mb
454
+
455
+ if features_used is not None:
456
+ payload["features_used"] = features_used
457
+
458
+ return TelemetryEvent(
459
+ event_id=generate_event_id(),
460
+ event_type=EventType.SESSION_END.value,
461
+ timestamp=_get_utc_timestamp(),
462
+ priority="critical",
463
+ payload=payload,
464
+ org_id=org_id,
465
+ team_id=team_id,
466
+ )
467
+
468
+
469
+ # =============================================================================
470
+ # Scan Event
471
+ # =============================================================================
472
+
473
+
474
+ def create_scan_event(
475
+ prompt_hash: str,
476
+ threat_detected: bool,
477
+ scan_duration_ms: float,
478
+ *,
479
+ event_id: str | None = None,
480
+ detection_count: int | None = None,
481
+ highest_severity: Literal["none", "low", "medium", "high", "critical"] | None = None,
482
+ rule_ids: list[str] | None = None,
483
+ families: list[str] | None = None,
484
+ l1_duration_ms: float | None = None,
485
+ l2_duration_ms: float | None = None,
486
+ l1_hit: bool | None = None,
487
+ l2_hit: bool | None = None,
488
+ l2_enabled: bool | None = None,
489
+ prompt_length: int | None = None,
490
+ action_taken: Literal["allow", "block", "warn", "redact"] | None = None,
491
+ entry_point: Literal["cli", "sdk", "wrapper", "integration"] | None = None,
492
+ wrapper_type: Literal["openai", "anthropic", "langchain", "none"] | None = None,
493
+ org_id: str | None = None,
494
+ team_id: str | None = None,
495
+ ) -> TelemetryEvent:
496
+ """Create a scan telemetry event.
497
+
498
+ Core telemetry event for each threat detection scan.
499
+
500
+ Args:
501
+ prompt_hash: SHA-256 hash of prompt for deduplication.
502
+ threat_detected: Whether any threat was detected.
503
+ scan_duration_ms: Total scan duration in milliseconds.
504
+ event_id: Optional event ID. If not provided, one will be generated.
505
+ detection_count: Number of detections found.
506
+ highest_severity: Highest severity among detections.
507
+ rule_ids: List of triggered rule IDs (up to 10).
508
+ families: Threat families detected (PI, JB, PII, etc.).
509
+ l1_duration_ms: L1 (rule-based) scan duration.
510
+ l2_duration_ms: L2 (ML-based) scan duration.
511
+ l1_hit: L1 detection triggered.
512
+ l2_hit: L2 detection triggered.
513
+ l2_enabled: Whether L2 was enabled for this scan.
514
+ prompt_length: Character length of scanned prompt.
515
+ action_taken: Action taken based on policy.
516
+ entry_point: How the scan was triggered.
517
+ wrapper_type: Wrapper used if applicable.
518
+ org_id: Organization ID for multi-tenant tracking.
519
+ team_id: Team ID for team-level analytics.
520
+
521
+ Returns:
522
+ TelemetryEvent with scan payload. Priority is critical if
523
+ highest_severity is HIGH or CRITICAL, otherwise standard.
524
+
525
+ Example:
526
+ >>> event = create_scan_event(
527
+ ... prompt_hash="a" * 64,
528
+ ... threat_detected=True,
529
+ ... scan_duration_ms=4.5,
530
+ ... detection_count=2,
531
+ ... highest_severity="HIGH",
532
+ ... rule_ids=["pi-001", "pi-002"],
533
+ ... families=["PI"],
534
+ ... org_id="org_123",
535
+ ... team_id="team_456",
536
+ ... )
537
+ """
538
+ payload: dict[str, Any] = {
539
+ "prompt_hash": prompt_hash,
540
+ "threat_detected": threat_detected,
541
+ "scan_duration_ms": scan_duration_ms,
542
+ }
543
+
544
+ if detection_count is not None:
545
+ payload["detection_count"] = detection_count
546
+
547
+ if highest_severity is not None:
548
+ payload["highest_severity"] = highest_severity
549
+
550
+ if rule_ids is not None:
551
+ # Limit to 10 rule IDs as per schema
552
+ payload["rule_ids"] = rule_ids[:10]
553
+
554
+ if families is not None:
555
+ payload["families"] = families
556
+
557
+ if l1_duration_ms is not None:
558
+ payload["l1_duration_ms"] = l1_duration_ms
559
+
560
+ if l2_duration_ms is not None:
561
+ payload["l2_duration_ms"] = l2_duration_ms
562
+
563
+ if l1_hit is not None:
564
+ payload["l1_hit"] = l1_hit
565
+
566
+ if l2_hit is not None:
567
+ payload["l2_hit"] = l2_hit
568
+
569
+ if l2_enabled is not None:
570
+ payload["l2_enabled"] = l2_enabled
571
+
572
+ if prompt_length is not None:
573
+ payload["prompt_length"] = prompt_length
574
+
575
+ if action_taken is not None:
576
+ payload["action_taken"] = action_taken
577
+
578
+ if entry_point is not None:
579
+ payload["entry_point"] = entry_point
580
+
581
+ if wrapper_type is not None:
582
+ payload["wrapper_type"] = wrapper_type
583
+
584
+ # Priority is critical if threat is HIGH or CRITICAL severity
585
+ priority: Literal["critical", "standard"] = "standard"
586
+ if highest_severity in ("high", "critical"):
587
+ priority = "critical"
588
+
589
+ return TelemetryEvent(
590
+ event_id=event_id if event_id else generate_event_id(),
591
+ event_type=EventType.SCAN.value,
592
+ timestamp=_get_utc_timestamp(),
593
+ priority=priority,
594
+ payload=payload,
595
+ org_id=org_id,
596
+ team_id=team_id,
597
+ )
598
+
599
+
600
+ # =============================================================================
601
+ # Scan Event v2.0 (Full L2 Telemetry)
602
+ # =============================================================================
603
+
604
+ # Schema version for v2 events
605
+ SCAN_SCHEMA_VERSION = "2.0.0"
606
+
607
+
608
+ def create_scan_event_v2(
609
+ payload: dict[str, Any],
610
+ *,
611
+ event_id: str | None = None,
612
+ org_id: str | None = None,
613
+ team_id: str | None = None,
614
+ ) -> TelemetryEvent:
615
+ """Create a scan telemetry event using schema v2.0.
616
+
617
+ This function accepts a pre-built payload from ScanTelemetryBuilder.
618
+ The payload must conform to SCAN_TELEMETRY_SCHEMA.md.
619
+
620
+ Args:
621
+ payload: Pre-built payload dict from ScanTelemetryBuilder.build()
622
+ event_id: Optional event ID. If not provided, one will be generated.
623
+ org_id: Organization ID for multi-tenant tracking.
624
+ team_id: Team ID for team-level analytics.
625
+
626
+ Returns:
627
+ TelemetryEvent with scan payload and schema_version.
628
+
629
+ Example:
630
+ >>> from raxe.domain.telemetry.scan_telemetry_builder import build_scan_telemetry
631
+ >>> payload = build_scan_telemetry(prompt, l1_result, l2_result, duration_ms)
632
+ >>> event = create_scan_event_v2(payload)
633
+ """
634
+ # Add schema version to payload
635
+ payload_with_version = {"schema_version": SCAN_SCHEMA_VERSION, **payload}
636
+
637
+ # Determine priority from L1/L2 severity
638
+ priority: Literal["critical", "standard"] = "standard"
639
+
640
+ # Check L1 severity
641
+ l1_block = payload.get("l1", {})
642
+ if l1_block.get("highest_severity") in ("high", "critical"):
643
+ priority = "critical"
644
+
645
+ # Check L2 classification
646
+ l2_block = payload.get("l2", {})
647
+ if l2_block.get("classification") in ("HIGH_THREAT", "THREAT"):
648
+ priority = "critical"
649
+
650
+ # Also critical if threat detected
651
+ if payload.get("threat_detected"):
652
+ priority = "critical"
653
+
654
+ return TelemetryEvent(
655
+ event_id=event_id if event_id else generate_event_id(),
656
+ event_type=EventType.SCAN.value,
657
+ timestamp=_get_utc_timestamp(),
658
+ priority=priority,
659
+ payload=payload_with_version,
660
+ org_id=org_id,
661
+ team_id=team_id,
662
+ )
663
+
664
+
665
+ # =============================================================================
666
+ # Error Event
667
+ # =============================================================================
668
+
669
+
670
+ def create_error_event(
671
+ error_type: Literal[
672
+ "validation_error",
673
+ "configuration_error",
674
+ "rule_loading_error",
675
+ "ml_model_error",
676
+ "network_error",
677
+ "permission_error",
678
+ "timeout_error",
679
+ "internal_error",
680
+ ],
681
+ error_code: str,
682
+ component: Literal["cli", "sdk", "engine", "ml", "rules", "config", "telemetry", "wrapper"],
683
+ *,
684
+ error_message_hash: str | None = None,
685
+ operation: str | None = None,
686
+ is_recoverable: bool | None = None,
687
+ stack_trace_hash: str | None = None,
688
+ context: dict[str, str] | None = None,
689
+ org_id: str | None = None,
690
+ team_id: str | None = None,
691
+ ) -> TelemetryEvent:
692
+ """Create an error telemetry event.
693
+
694
+ Fired when an error occurs (for debugging and quality improvement).
695
+
696
+ Args:
697
+ error_type: Category of error.
698
+ error_code: Specific error code (e.g., RAXE_001).
699
+ component: Component where error occurred.
700
+ error_message_hash: SHA-256 hash of error message (for grouping without PII).
701
+ operation: Operation being performed when error occurred.
702
+ is_recoverable: Whether the error was recovered from.
703
+ stack_trace_hash: SHA-256 hash of stack trace (for grouping).
704
+ context: Non-sensitive error context (python_version, raxe_version, platform).
705
+ org_id: Organization ID for multi-tenant tracking.
706
+ team_id: Team ID for team-level analytics.
707
+
708
+ Returns:
709
+ TelemetryEvent with error payload.
710
+
711
+ Example:
712
+ >>> event = create_error_event(
713
+ ... error_type="validation_error",
714
+ ... error_code="RAXE_001",
715
+ ... component="engine",
716
+ ... error_message_hash=hash_text("Invalid prompt format"),
717
+ ... operation="scan",
718
+ ... is_recoverable=True,
719
+ ... org_id="org_123",
720
+ ... team_id="team_456",
721
+ ... )
722
+ """
723
+ payload: dict[str, Any] = {
724
+ "error_type": error_type,
725
+ "error_code": error_code,
726
+ "component": component,
727
+ }
728
+
729
+ if error_message_hash is not None:
730
+ payload["error_message_hash"] = error_message_hash
731
+
732
+ if operation is not None:
733
+ payload["operation"] = operation
734
+
735
+ if is_recoverable is not None:
736
+ payload["is_recoverable"] = is_recoverable
737
+
738
+ if stack_trace_hash is not None:
739
+ payload["stack_trace_hash"] = stack_trace_hash
740
+
741
+ if context is not None:
742
+ payload["context"] = context
743
+
744
+ return TelemetryEvent(
745
+ event_id=generate_event_id(),
746
+ event_type=EventType.ERROR.value,
747
+ timestamp=_get_utc_timestamp(),
748
+ priority="critical",
749
+ payload=payload,
750
+ org_id=org_id,
751
+ team_id=team_id,
752
+ )
753
+
754
+
755
+ # =============================================================================
756
+ # Performance Event
757
+ # =============================================================================
758
+
759
+
760
+ def create_performance_event(
761
+ period_start: str,
762
+ period_end: str,
763
+ scan_count: int,
764
+ *,
765
+ latency_percentiles: dict[str, float] | None = None,
766
+ l1_latency_percentiles: dict[str, float] | None = None,
767
+ l2_latency_percentiles: dict[str, float] | None = None,
768
+ memory_usage: dict[str, float] | None = None,
769
+ threat_detection_rate: float | None = None,
770
+ rules_loaded: int | None = None,
771
+ l2_enabled: bool | None = None,
772
+ org_id: str | None = None,
773
+ team_id: str | None = None,
774
+ ) -> TelemetryEvent:
775
+ """Create a performance telemetry event.
776
+
777
+ Aggregated performance metrics (sent periodically).
778
+
779
+ Args:
780
+ period_start: Start of measurement period (ISO 8601).
781
+ period_end: End of measurement period (ISO 8601).
782
+ scan_count: Number of scans in period.
783
+ latency_percentiles: Scan latency distribution (p50_ms, p95_ms, p99_ms, max_ms).
784
+ l1_latency_percentiles: L1 scan latency distribution.
785
+ l2_latency_percentiles: L2 scan latency distribution.
786
+ memory_usage: Memory usage statistics (current_mb, peak_mb).
787
+ threat_detection_rate: Percentage of scans with threats detected (0.0-1.0).
788
+ rules_loaded: Number of rules loaded.
789
+ l2_enabled: Whether L2 ML detection is enabled.
790
+ org_id: Organization ID for multi-tenant tracking.
791
+ team_id: Team ID for team-level analytics.
792
+
793
+ Returns:
794
+ TelemetryEvent with performance payload.
795
+
796
+ Example:
797
+ >>> event = create_performance_event(
798
+ ... period_start="2025-01-22T10:00:00Z",
799
+ ... period_end="2025-01-22T11:00:00Z",
800
+ ... scan_count=1000,
801
+ ... latency_percentiles={"p50_ms": 2.5, "p95_ms": 8.0, "p99_ms": 12.0},
802
+ ... threat_detection_rate=0.05,
803
+ ... org_id="org_123",
804
+ ... team_id="team_456",
805
+ ... )
806
+ """
807
+ payload: dict[str, Any] = {
808
+ "period_start": period_start,
809
+ "period_end": period_end,
810
+ "scan_count": scan_count,
811
+ }
812
+
813
+ if latency_percentiles is not None:
814
+ payload["latency_percentiles"] = latency_percentiles
815
+
816
+ if l1_latency_percentiles is not None:
817
+ payload["l1_latency_percentiles"] = l1_latency_percentiles
818
+
819
+ if l2_latency_percentiles is not None:
820
+ payload["l2_latency_percentiles"] = l2_latency_percentiles
821
+
822
+ if memory_usage is not None:
823
+ payload["memory_usage"] = memory_usage
824
+
825
+ if threat_detection_rate is not None:
826
+ payload["threat_detection_rate"] = threat_detection_rate
827
+
828
+ if rules_loaded is not None:
829
+ payload["rules_loaded"] = rules_loaded
830
+
831
+ if l2_enabled is not None:
832
+ payload["l2_enabled"] = l2_enabled
833
+
834
+ return TelemetryEvent(
835
+ event_id=generate_event_id(),
836
+ event_type=EventType.PERFORMANCE.value,
837
+ timestamp=_get_utc_timestamp(),
838
+ priority="standard",
839
+ payload=payload,
840
+ org_id=org_id,
841
+ team_id=team_id,
842
+ )
843
+
844
+
845
+ # =============================================================================
846
+ # Feature Usage Event
847
+ # =============================================================================
848
+
849
+
850
+ def create_feature_usage_event(
851
+ feature: Literal[
852
+ "cli_scan",
853
+ "cli_rules_list",
854
+ "cli_rules_show",
855
+ "cli_config",
856
+ "cli_stats",
857
+ "cli_repl",
858
+ "cli_explain",
859
+ "cli_validate_rule",
860
+ "cli_doctor",
861
+ "cli_telemetry_dlq",
862
+ "sdk_scan",
863
+ "sdk_batch_scan",
864
+ "sdk_layer_control",
865
+ "wrapper_openai",
866
+ "wrapper_anthropic",
867
+ "integration_langchain",
868
+ "custom_rule_loaded",
869
+ "policy_applied",
870
+ ],
871
+ action: Literal["invoked", "completed", "failed", "cancelled"],
872
+ *,
873
+ duration_ms: float | None = None,
874
+ success: bool | None = None,
875
+ metadata: dict[str, Any] | None = None,
876
+ org_id: str | None = None,
877
+ team_id: str | None = None,
878
+ ) -> TelemetryEvent:
879
+ """Create a feature usage telemetry event.
880
+
881
+ Tracks usage of specific features for product analytics.
882
+
883
+ Args:
884
+ feature: Feature being used.
885
+ action: Action taken with feature.
886
+ duration_ms: Time spent using feature.
887
+ success: Whether feature usage was successful.
888
+ metadata: Feature-specific non-sensitive metadata.
889
+ org_id: Organization ID for multi-tenant tracking.
890
+ team_id: Team ID for team-level analytics.
891
+
892
+ Returns:
893
+ TelemetryEvent with feature_usage payload.
894
+
895
+ Example:
896
+ >>> event = create_feature_usage_event(
897
+ ... feature="cli_scan",
898
+ ... action="completed",
899
+ ... duration_ms=150.5,
900
+ ... success=True,
901
+ ... metadata={"output_format": "json"},
902
+ ... org_id="org_123",
903
+ ... team_id="team_456",
904
+ ... )
905
+ """
906
+ payload: dict[str, Any] = {
907
+ "feature": feature,
908
+ "action": action,
909
+ }
910
+
911
+ if duration_ms is not None:
912
+ payload["duration_ms"] = duration_ms
913
+
914
+ if success is not None:
915
+ payload["success"] = success
916
+
917
+ if metadata is not None:
918
+ payload["metadata"] = metadata
919
+
920
+ return TelemetryEvent(
921
+ event_id=generate_event_id(),
922
+ event_type=EventType.FEATURE_USAGE.value,
923
+ timestamp=_get_utc_timestamp(),
924
+ priority="standard",
925
+ payload=payload,
926
+ org_id=org_id,
927
+ team_id=team_id,
928
+ )
929
+
930
+
931
+ # =============================================================================
932
+ # Heartbeat Event
933
+ # =============================================================================
934
+
935
+
936
+ def create_heartbeat_event(
937
+ uptime_seconds: float,
938
+ scans_since_last_heartbeat: int,
939
+ *,
940
+ threats_since_last_heartbeat: int | None = None,
941
+ memory_mb: float | None = None,
942
+ queue_depths: dict[str, int] | None = None,
943
+ circuit_breaker_state: Literal["closed", "open", "half_open"] | None = None,
944
+ last_successful_ship: str | None = None,
945
+ org_id: str | None = None,
946
+ team_id: str | None = None,
947
+ ) -> TelemetryEvent:
948
+ """Create a heartbeat telemetry event.
949
+
950
+ Periodic health signal for long-running processes.
951
+
952
+ Args:
953
+ uptime_seconds: Time since process started.
954
+ scans_since_last_heartbeat: Scans performed since last heartbeat.
955
+ threats_since_last_heartbeat: Threats detected since last heartbeat.
956
+ memory_mb: Current memory usage.
957
+ queue_depths: Current telemetry queue sizes (critical, standard, dlq).
958
+ circuit_breaker_state: Current circuit breaker state.
959
+ last_successful_ship: Timestamp of last successful telemetry ship.
960
+ org_id: Organization ID for multi-tenant tracking.
961
+ team_id: Team ID for team-level analytics.
962
+
963
+ Returns:
964
+ TelemetryEvent with heartbeat payload.
965
+
966
+ Example:
967
+ >>> event = create_heartbeat_event(
968
+ ... uptime_seconds=3600.0,
969
+ ... scans_since_last_heartbeat=100,
970
+ ... threats_since_last_heartbeat=5,
971
+ ... memory_mb=120.5,
972
+ ... queue_depths={"critical": 0, "standard": 10, "dlq": 2},
973
+ ... circuit_breaker_state="closed",
974
+ ... org_id="org_123",
975
+ ... team_id="team_456",
976
+ ... )
977
+ """
978
+ payload: dict[str, Any] = {
979
+ "uptime_seconds": uptime_seconds,
980
+ "scans_since_last_heartbeat": scans_since_last_heartbeat,
981
+ }
982
+
983
+ if threats_since_last_heartbeat is not None:
984
+ payload["threats_since_last_heartbeat"] = threats_since_last_heartbeat
985
+
986
+ if memory_mb is not None:
987
+ payload["memory_mb"] = memory_mb
988
+
989
+ if queue_depths is not None:
990
+ payload["queue_depths"] = queue_depths
991
+
992
+ if circuit_breaker_state is not None:
993
+ payload["circuit_breaker_state"] = circuit_breaker_state
994
+
995
+ if last_successful_ship is not None:
996
+ payload["last_successful_ship"] = last_successful_ship
997
+
998
+ return TelemetryEvent(
999
+ event_id=generate_event_id(),
1000
+ event_type=EventType.HEARTBEAT.value,
1001
+ timestamp=_get_utc_timestamp(),
1002
+ priority="standard",
1003
+ payload=payload,
1004
+ org_id=org_id,
1005
+ team_id=team_id,
1006
+ )
1007
+
1008
+
1009
+ # =============================================================================
1010
+ # Key Upgrade Event
1011
+ # =============================================================================
1012
+
1013
+
1014
+ def create_key_upgrade_event(
1015
+ previous_key_type: Literal["temp", "community", "pro", "enterprise"],
1016
+ new_key_type: Literal["community", "pro", "enterprise"],
1017
+ *,
1018
+ previous_key_id: str | None = None,
1019
+ new_key_id: str | None = None,
1020
+ days_on_previous: int | None = None,
1021
+ scans_on_previous: int | None = None,
1022
+ threats_on_previous: int | None = None,
1023
+ conversion_trigger: Literal[
1024
+ "trial_expiry",
1025
+ "rate_limit_hit",
1026
+ "feature_needed",
1027
+ "manual_upgrade",
1028
+ "promo_code",
1029
+ "cli_connect",
1030
+ ]
1031
+ | None = None,
1032
+ org_id: str | None = None,
1033
+ team_id: str | None = None,
1034
+ ) -> TelemetryEvent:
1035
+ """Create a key upgrade telemetry event.
1036
+
1037
+ Fired when API key is upgraded (conversion tracking). Includes key IDs
1038
+ to enable server-side linking of historical events from the old key
1039
+ to the new key.
1040
+
1041
+ Args:
1042
+ previous_key_type: Previous key tier.
1043
+ new_key_type: New key tier.
1044
+ previous_key_id: BigQuery-compatible ID for previous key (e.g., "key_23cc2f9f21f9").
1045
+ Computed as "key_" + SHA256(api_key)[:12].
1046
+ new_key_id: BigQuery-compatible ID for new key (e.g., "key_7ce219b525f1").
1047
+ Computed as "key_" + SHA256(api_key)[:12].
1048
+ days_on_previous: Days spent on previous tier.
1049
+ scans_on_previous: Total scans on previous tier.
1050
+ threats_on_previous: Total threats detected on previous tier.
1051
+ conversion_trigger: What triggered the upgrade.
1052
+ org_id: Organization ID for multi-tenant tracking.
1053
+ team_id: Team ID for team-level analytics.
1054
+
1055
+ Returns:
1056
+ TelemetryEvent with key_upgrade payload.
1057
+
1058
+ Example:
1059
+ >>> event = create_key_upgrade_event(
1060
+ ... previous_key_type="temp",
1061
+ ... new_key_type="community",
1062
+ ... previous_key_id="key_23cc2f9f21f9",
1063
+ ... new_key_id="key_7ce219b525f1",
1064
+ ... days_on_previous=7,
1065
+ ... scans_on_previous=500,
1066
+ ... threats_on_previous=25,
1067
+ ... conversion_trigger="trial_expiry",
1068
+ ... org_id="org_123",
1069
+ ... team_id="team_456",
1070
+ ... )
1071
+ """
1072
+ payload: dict[str, Any] = {
1073
+ "previous_key_type": previous_key_type,
1074
+ "new_key_type": new_key_type,
1075
+ }
1076
+
1077
+ # Add key IDs for server-side event linking
1078
+ if previous_key_id is not None:
1079
+ payload["previous_key_id"] = previous_key_id
1080
+
1081
+ if new_key_id is not None:
1082
+ payload["new_key_id"] = new_key_id
1083
+
1084
+ if days_on_previous is not None:
1085
+ payload["days_on_previous"] = days_on_previous
1086
+
1087
+ if scans_on_previous is not None:
1088
+ payload["scans_on_previous"] = scans_on_previous
1089
+
1090
+ if threats_on_previous is not None:
1091
+ payload["threats_on_previous"] = threats_on_previous
1092
+
1093
+ if conversion_trigger is not None:
1094
+ payload["conversion_trigger"] = conversion_trigger
1095
+
1096
+ return TelemetryEvent(
1097
+ event_id=generate_event_id(),
1098
+ event_type=EventType.KEY_UPGRADE.value,
1099
+ timestamp=_get_utc_timestamp(),
1100
+ priority="critical",
1101
+ payload=payload,
1102
+ org_id=org_id,
1103
+ team_id=team_id,
1104
+ )
1105
+
1106
+
1107
+ # =============================================================================
1108
+ # Config Changed Event
1109
+ # =============================================================================
1110
+
1111
+
1112
+ def create_config_changed_event(
1113
+ changed_via: Literal["cli", "sdk", "config_file", "env_var"],
1114
+ changes: list[dict[str, Any]],
1115
+ *,
1116
+ is_final_event: bool = False,
1117
+ org_id: str | None = None,
1118
+ team_id: str | None = None,
1119
+ ) -> TelemetryEvent:
1120
+ """Create a config changed telemetry event.
1121
+
1122
+ Fired when configuration is changed (tracks opt-outs and preferences).
1123
+
1124
+ Args:
1125
+ changed_via: How configuration was changed.
1126
+ changes: List of configuration changes. Each change should have:
1127
+ - key: Configuration key that changed (e.g., "telemetry.enabled")
1128
+ - new_value: New value
1129
+ - old_value: Previous value (optional)
1130
+ is_final_event: True if this is the last event before telemetry disable.
1131
+ org_id: Organization ID for multi-tenant tracking.
1132
+ team_id: Team ID for team-level analytics.
1133
+
1134
+ Returns:
1135
+ TelemetryEvent with config_changed payload. Priority is critical
1136
+ if telemetry is being disabled (is_final_event=True), otherwise standard.
1137
+
1138
+ Example:
1139
+ >>> event = create_config_changed_event(
1140
+ ... changed_via="cli",
1141
+ ... changes=[
1142
+ ... {"key": "telemetry.enabled", "old_value": True, "new_value": False}
1143
+ ... ],
1144
+ ... is_final_event=True,
1145
+ ... org_id="org_123",
1146
+ ... team_id="team_456",
1147
+ ... )
1148
+ """
1149
+ payload: dict[str, Any] = {
1150
+ "changed_via": changed_via,
1151
+ "changes": changes,
1152
+ }
1153
+
1154
+ if is_final_event:
1155
+ payload["is_final_event"] = is_final_event
1156
+
1157
+ # Priority is critical if disabling telemetry (is_final_event=True)
1158
+ priority: Literal["critical", "standard"] = "critical" if is_final_event else "standard"
1159
+
1160
+ return TelemetryEvent(
1161
+ event_id=generate_event_id(),
1162
+ event_type=EventType.CONFIG_CHANGED.value,
1163
+ timestamp=_get_utc_timestamp(),
1164
+ priority=priority,
1165
+ payload=payload,
1166
+ org_id=org_id,
1167
+ team_id=team_id,
1168
+ )
1169
+
1170
+
1171
+ # =============================================================================
1172
+ # Team Invite Event
1173
+ # =============================================================================
1174
+
1175
+
1176
+ def create_team_invite_event(
1177
+ inviter_installation_id: str,
1178
+ invitee_email_hash: str,
1179
+ org_id: str,
1180
+ team_id: str,
1181
+ role: Literal["admin", "member", "viewer"],
1182
+ *,
1183
+ invite_method: Literal["email", "link", "api"] = "email",
1184
+ ) -> TelemetryEvent:
1185
+ """Create a team invite telemetry event.
1186
+
1187
+ Tracks team invitations for viral growth metrics.
1188
+
1189
+ Args:
1190
+ inviter_installation_id: Installation ID of the user sending the invite.
1191
+ invitee_email_hash: SHA-256 hash of invitee's email (privacy-preserving).
1192
+ org_id: Organization identifier.
1193
+ team_id: Team identifier within the organization.
1194
+ role: Role being assigned to the invitee.
1195
+ invite_method: How the invitation was sent.
1196
+
1197
+ Returns:
1198
+ TelemetryEvent with team_invite payload (critical priority).
1199
+
1200
+ Example:
1201
+ >>> event = create_team_invite_event(
1202
+ ... inviter_installation_id="inst_abc123def456789",
1203
+ ... invitee_email_hash="a" * 64,
1204
+ ... org_id="org_123",
1205
+ ... team_id="team_456",
1206
+ ... role="member",
1207
+ ... invite_method="email",
1208
+ ... )
1209
+ """
1210
+ payload: dict[str, Any] = {
1211
+ "inviter_installation_id": inviter_installation_id,
1212
+ "invitee_email_hash": invitee_email_hash,
1213
+ "org_id": org_id,
1214
+ "team_id": team_id,
1215
+ "role": role,
1216
+ "invite_method": invite_method,
1217
+ }
1218
+
1219
+ return TelemetryEvent(
1220
+ event_id=generate_event_id(),
1221
+ event_type=EventType.TEAM_INVITE.value,
1222
+ timestamp=_get_utc_timestamp(),
1223
+ priority="critical",
1224
+ payload=payload,
1225
+ org_id=org_id,
1226
+ team_id=team_id,
1227
+ )
1228
+
1229
+
1230
+ # =============================================================================
1231
+ # Utility Functions
1232
+ # =============================================================================
1233
+
1234
+
1235
+ def create_prompt_hash(prompt: str) -> str:
1236
+ """Create a SHA-256 hash of a prompt for telemetry.
1237
+
1238
+ This is a convenience wrapper around hash_text for scan events.
1239
+
1240
+ Args:
1241
+ prompt: The prompt text to hash.
1242
+
1243
+ Returns:
1244
+ 71-character prefixed SHA-256 hash string (sha256:<64_hex_chars>).
1245
+
1246
+ Example:
1247
+ >>> create_prompt_hash("Hello, world!")
1248
+ 'sha256:315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3'
1249
+ """
1250
+ return hash_text(prompt, algorithm="sha256")
1251
+
1252
+
1253
+ def event_to_dict(event: TelemetryEvent) -> dict[str, Any]:
1254
+ """Convert a TelemetryEvent to a dictionary for serialization.
1255
+
1256
+ Args:
1257
+ event: The telemetry event to convert.
1258
+
1259
+ Returns:
1260
+ Dictionary representation of the event including org_id and team_id if present.
1261
+
1262
+ Example:
1263
+ >>> event = create_heartbeat_event(uptime_seconds=100.0, scans_since_last_heartbeat=5)
1264
+ >>> d = event_to_dict(event)
1265
+ >>> d["event_type"]
1266
+ 'heartbeat'
1267
+ """
1268
+ result: dict[str, Any] = {
1269
+ "event_id": event.event_id,
1270
+ "event_type": event.event_type,
1271
+ "timestamp": event.timestamp,
1272
+ "priority": event.priority,
1273
+ "payload": event.payload,
1274
+ }
1275
+
1276
+ if event.org_id is not None:
1277
+ result["org_id"] = event.org_id
1278
+
1279
+ if event.team_id is not None:
1280
+ result["team_id"] = event.team_id
1281
+
1282
+ return result