howler-api 4.0.0.dev1207__tar.gz → 4.0.0.dev1246__tar.gz

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 (204) hide show
  1. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/PKG-INFO +1 -1
  2. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/cronjobs/retention.py +67 -2
  3. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/config.py +27 -0
  4. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/pyproject.toml +1 -1
  5. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/README.md +0 -0
  6. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/__init__.py +0 -0
  7. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/actions/__init__.py +0 -0
  8. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/actions/add_label.py +0 -0
  9. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/actions/add_to_bundle.py +0 -0
  10. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/actions/change_field.py +0 -0
  11. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/actions/demote.py +0 -0
  12. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/actions/example_plugin.py +0 -0
  13. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/actions/prioritization.py +0 -0
  14. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/actions/promote.py +0 -0
  15. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/actions/remove_from_bundle.py +0 -0
  16. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/actions/remove_label.py +0 -0
  17. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/actions/transition.py +0 -0
  18. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/__init__.py +0 -0
  19. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/base.py +0 -0
  20. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/socket.py +0 -0
  21. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/__init__.py +0 -0
  22. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/action.py +0 -0
  23. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/analytic.py +0 -0
  24. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/auth.py +0 -0
  25. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/clue.py +0 -0
  26. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/configs.py +0 -0
  27. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/dossier.py +0 -0
  28. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/help.py +0 -0
  29. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/hit.py +0 -0
  30. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/notebook.py +0 -0
  31. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/overview.py +0 -0
  32. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/search.py +0 -0
  33. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/template.py +0 -0
  34. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/tool.py +0 -0
  35. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/user.py +0 -0
  36. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/utils/__init__.py +0 -0
  37. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/utils/etag.py +0 -0
  38. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/utils/params.py +0 -0
  39. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/api/v1/view.py +0 -0
  40. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/app.py +0 -0
  41. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/common/README.md +0 -0
  42. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/common/__init__.py +0 -0
  43. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/common/classification.py +0 -0
  44. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/common/classification.yml +0 -0
  45. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/common/exceptions.py +0 -0
  46. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/common/loader.py +0 -0
  47. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/common/logging/__init__.py +0 -0
  48. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/common/logging/audit.py +0 -0
  49. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/common/logging/format.py +0 -0
  50. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/common/net.py +0 -0
  51. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/common/net_static.py +0 -0
  52. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/common/random_user.py +0 -0
  53. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/common/swagger.py +0 -0
  54. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/config.py +0 -0
  55. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/cronjobs/__init__.py +0 -0
  56. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/cronjobs/action_queue_worker.py +0 -0
  57. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/cronjobs/rules.py +0 -0
  58. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/cronjobs/view_cleanup.py +0 -0
  59. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/README.md +0 -0
  60. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/__init__.py +0 -0
  61. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/bulk.py +0 -0
  62. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/collection.py +0 -0
  63. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/constants.py +0 -0
  64. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/exceptions.py +0 -0
  65. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/howler_store.py +0 -0
  66. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/migrations/fix_process.py +0 -0
  67. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/operations.py +0 -0
  68. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/schemas.py +0 -0
  69. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/store.py +0 -0
  70. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/support/__init__.py +0 -0
  71. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/support/build.py +0 -0
  72. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/support/schemas.py +0 -0
  73. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/datastore/types.py +0 -0
  74. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/error.py +0 -0
  75. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/external/README.md +0 -0
  76. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/external/__init__.py +0 -0
  77. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/external/generate_mitre.py +0 -0
  78. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/external/generate_sigma_rules.py +0 -0
  79. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/external/generate_tlds.py +0 -0
  80. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/external/reindex_data.py +0 -0
  81. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/external/wipe_databases.py +0 -0
  82. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/gunicorn_config.py +0 -0
  83. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/healthz.py +0 -0
  84. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/helper/__init__.py +0 -0
  85. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/helper/azure.py +0 -0
  86. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/helper/discover.py +0 -0
  87. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/helper/hit.py +0 -0
  88. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/helper/oauth.py +0 -0
  89. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/helper/search.py +0 -0
  90. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/helper/workflow.py +0 -0
  91. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/helper/ws.py +0 -0
  92. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/README.md +0 -0
  93. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/__init__.py +0 -0
  94. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/base.py +0 -0
  95. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/charter.txt +0 -0
  96. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/helper.py +0 -0
  97. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/howler_enum.py +0 -0
  98. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/__init__.py +0 -0
  99. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/action.py +0 -0
  100. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/analytic.py +0 -0
  101. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/assemblyline.py +0 -0
  102. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/aws.py +0 -0
  103. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/azure.py +0 -0
  104. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/cbs.py +0 -0
  105. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/clue.py +0 -0
  106. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/dossier.py +0 -0
  107. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/__init__.py +0 -0
  108. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/agent.py +0 -0
  109. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/autonomous_system.py +0 -0
  110. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/client.py +0 -0
  111. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/cloud.py +0 -0
  112. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/code_signature.py +0 -0
  113. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/container.py +0 -0
  114. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/dns.py +0 -0
  115. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/egress.py +0 -0
  116. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/elf.py +0 -0
  117. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/email.py +0 -0
  118. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/error.py +0 -0
  119. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/event.py +0 -0
  120. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/faas.py +0 -0
  121. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/file.py +0 -0
  122. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/geo.py +0 -0
  123. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/group.py +0 -0
  124. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/hash.py +0 -0
  125. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/host.py +0 -0
  126. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/http.py +0 -0
  127. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/ingress.py +0 -0
  128. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/interface.py +0 -0
  129. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/network.py +0 -0
  130. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/observer.py +0 -0
  131. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/organization.py +0 -0
  132. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/os.py +0 -0
  133. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/pe.py +0 -0
  134. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/process.py +0 -0
  135. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/registry.py +0 -0
  136. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/related.py +0 -0
  137. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/rule.py +0 -0
  138. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/server.py +0 -0
  139. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/threat.py +0 -0
  140. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/tls.py +0 -0
  141. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/url.py +0 -0
  142. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/user.py +0 -0
  143. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/user_agent.py +0 -0
  144. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/ecs/vulnerability.py +0 -0
  145. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/gcp.py +0 -0
  146. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/hit.py +0 -0
  147. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/howler_data.py +0 -0
  148. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/lead.py +0 -0
  149. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/localized_label.py +0 -0
  150. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/overview.py +0 -0
  151. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/pivot.py +0 -0
  152. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/template.py +0 -0
  153. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/user.py +0 -0
  154. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/models/view.py +0 -0
  155. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/random_data.py +0 -0
  156. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/odm/randomizer.py +0 -0
  157. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/patched.py +0 -0
  158. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/plugins/__init__.py +0 -0
  159. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/plugins/config.py +0 -0
  160. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/remote/__init__.py +0 -0
  161. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/remote/datatypes/README.md +0 -0
  162. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/remote/datatypes/__init__.py +0 -0
  163. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/remote/datatypes/counters.py +0 -0
  164. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/remote/datatypes/events.py +0 -0
  165. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/remote/datatypes/hash.py +0 -0
  166. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/remote/datatypes/lock.py +0 -0
  167. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/remote/datatypes/queues/__init__.py +0 -0
  168. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/remote/datatypes/queues/comms.py +0 -0
  169. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/remote/datatypes/queues/multi.py +0 -0
  170. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/remote/datatypes/queues/named.py +0 -0
  171. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/remote/datatypes/queues/priority.py +0 -0
  172. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/remote/datatypes/set.py +0 -0
  173. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/remote/datatypes/user_quota_tracker.py +0 -0
  174. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/security/__init__.py +0 -0
  175. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/security/socket.py +0 -0
  176. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/security/utils.py +0 -0
  177. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/services/__init__.py +0 -0
  178. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/services/action_service.py +0 -0
  179. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/services/analytic_service.py +0 -0
  180. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/services/auth_service.py +0 -0
  181. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/services/config_service.py +0 -0
  182. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/services/dossier_service.py +0 -0
  183. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/services/event_service.py +0 -0
  184. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/services/hit_service.py +0 -0
  185. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/services/jwt_service.py +0 -0
  186. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/services/lucene_service.py +0 -0
  187. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/services/notebook_service.py +0 -0
  188. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/services/overview_service.py +0 -0
  189. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/services/template_service.py +0 -0
  190. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/services/user_service.py +0 -0
  191. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/telemetry.py +0 -0
  192. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/utils/__init__.py +0 -0
  193. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/utils/annotations.py +0 -0
  194. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/utils/chunk.py +0 -0
  195. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/utils/compat.py +0 -0
  196. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/utils/constants.py +0 -0
  197. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/utils/dict_utils.py +0 -0
  198. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/utils/isotime.py +0 -0
  199. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/utils/list_utils.py +0 -0
  200. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/utils/lucene.py +0 -0
  201. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/utils/path.py +0 -0
  202. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/utils/socket_utils.py +0 -0
  203. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/utils/str_utils.py +0 -0
  204. {howler_api-4.0.0.dev1207 → howler_api-4.0.0.dev1246}/howler/utils/uid.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: howler-api
3
- Version: 4.0.0.dev1207
3
+ Version: 4.0.0.dev1246
4
4
  Summary: Howler - API server
5
5
  License: MIT
6
6
  Keywords: howler,alerting,gc,canada,cse-cst,cse,cst,cyber,cccs
@@ -31,12 +31,74 @@ def execute():
31
31
 
32
32
  logger.debug("Deletion complete")
33
33
 
34
+ _execute_rules(ds)
35
+
34
36
  logger.debug("Cleaning analytics with no matching hits")
35
37
  _remove_analytics_without_hits(ds)
36
38
 
37
39
 
38
- def _remove_analytics_without_hits(ds: HowlerDatastore):
40
+ def _execute_rules(ds: HowlerDatastore) -> None:
41
+ """Execute dynamic retention rules from config.
42
+
43
+ Iterates each enabled rule, computes its cutoff date, and deletes
44
+ hits that match the rule's query and are older than the cutoff.
45
+ Errors for individual rules are logged and skipped so that
46
+ remaining rules still execute. Emits a structured result log
47
+ for each rule execution.
48
+
49
+ Note: Rules are independent. If multiple rules match the same hit,
50
+ the hit is deleted by whichever rule runs first; subsequent matching
51
+ rules will no-op against the already-deleted document.
52
+
53
+ Args:
54
+ ds: Active HowlerDatastore instance.
55
+ """
56
+ rules = config.system.retention.rules
57
+ if not rules:
58
+ return
59
+
60
+ logger.info("Processing dynamic retention rules:")
61
+
62
+ for rule in rules:
63
+ result = {}
64
+
65
+ if not rule.enabled:
66
+ logger.debug("Skipping disabled retention rule '%s'", rule.name)
67
+ result = {"rule": rule.name, "status": "skipped", "reason": "disabled"}
68
+ logger.info("Rule result: '%s'", result)
69
+ continue
70
+
71
+ delta_kwargs = {str(rule.limit_unit): rule.limit_amount}
72
+ cutoff_dt = datetime.now(tz=timezone("UTC")) - timedelta(**delta_kwargs)
73
+ cutoff = cutoff_dt.strftime("%Y-%m-%dT%H:%M:%SZ")
74
+ combined_query = f"({rule.query}) AND event.created:{{* TO {cutoff}}}"
39
75
 
76
+ logger.debug(
77
+ "Executing retention rule '%s': query=%s cutoff=%s",
78
+ rule.name,
79
+ rule.query,
80
+ cutoff,
81
+ )
82
+
83
+ try:
84
+ count = ds.hit.count(combined_query, filters=None).get("count", -1)
85
+ ds.hit.delete_by_query(combined_query)
86
+ ds.hit.commit()
87
+ logger.debug("Retention rule '%s' complete", rule.name)
88
+ result = {"rule": rule.name, "status": "ok", "deleted": count, "cutoff": cutoff}
89
+ except Exception:
90
+ logger.error(
91
+ "Retention rule '%s' failed — skipping. query=%s",
92
+ rule.name,
93
+ combined_query,
94
+ exc_info=True,
95
+ )
96
+ result = {"rule": rule.name, "status": "error", "query": combined_query}
97
+
98
+ logger.info("Rule result: '%s'", result)
99
+
100
+
101
+ def _remove_analytics_without_hits(ds: HowlerDatastore):
40
102
  matched_analytics = _find_analytics_with_hits(ds)
41
103
 
42
104
  if matched_analytics is not None:
@@ -66,7 +128,6 @@ def _remove_analytics_without_hits(ds: HowlerDatastore):
66
128
 
67
129
 
68
130
  def _find_analytics_with_hits(ds: HowlerDatastore) -> list[str] | None:
69
-
70
131
  total_analytics = ds.analytic.count("id:*", filters=None)["count"]
71
132
 
72
133
  if total_analytics:
@@ -127,3 +188,7 @@ def setup_job(sched: BaseScheduler):
127
188
  **_kwargs,
128
189
  )
129
190
  logger.debug("Initialization complete")
191
+
192
+
193
+ if __name__ == "__main__":
194
+ execute()
@@ -356,6 +356,26 @@ class Auth(BaseModel):
356
356
  oauth: OAuth = OAuth()
357
357
 
358
358
 
359
+ class RetentionRule(BaseModel):
360
+ """A dynamic, query-scoped retention rule.
361
+
362
+ Pairs a Lucene query with a retention window. During the retention
363
+ cronjob run, hits matching the query that are older than the
364
+ specified window will be deleted.
365
+ """
366
+
367
+ name: str = Field(description="A human-readable label for this rule (used in logs).")
368
+ enabled: bool = Field(default=True, description="Whether this rule is active.")
369
+ query: str = Field(description="Lucene query that scopes which hits this rule applies to.")
370
+ limit_unit: Literal["days", "seconds", "microseconds", "milliseconds", "minutes", "hours", "weeks"] = Field(
371
+ default="days",
372
+ description="The unit to use when computing the retention limit for this rule.",
373
+ )
374
+ limit_amount: int = Field(
375
+ description="The number of limit_units to use when computing the retention limit for this rule.",
376
+ )
377
+
378
+
359
379
  class Retention(BaseModel):
360
380
  """Hit retention policy configuration.
361
381
 
@@ -382,6 +402,13 @@ class Retention(BaseModel):
382
402
  default="0 0 * * *",
383
403
  description="The crontab that denotes how often to run the retention job",
384
404
  )
405
+ rules: list[RetentionRule] = Field(
406
+ default=[],
407
+ description=(
408
+ "Optional list of dynamic retention rules. Each rule pairs a Lucene query "
409
+ "with a retention window. Rules run after the global sweep."
410
+ ),
411
+ )
385
412
 
386
413
 
387
414
  class ViewCleanup(BaseModel):
@@ -152,7 +152,7 @@ suppress-none-returning = true
152
152
  [tool.poetry]
153
153
  package-mode = true
154
154
  name = "howler-api"
155
- version = "4.0.0.dev1207"
155
+ version = "4.0.0.dev1246"
156
156
  description = "Howler - API server"
157
157
  authors = [
158
158
  "Canadian Centre for Cyber Security <howler@cyber.gc.ca>",