howler-api 4.1.0.dev1626__tar.gz → 4.1.0.dev1635__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 (239) hide show
  1. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/PKG-INFO +2 -1
  2. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/hit.py +3 -2
  3. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/cronjobs/retention.py +27 -5
  4. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/event.py +1 -21
  5. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/howler_data.py +1 -29
  6. howler_api-4.1.0.dev1635/howler/odm/models/log.py +31 -0
  7. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/case_service.py +30 -4
  8. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/hit_service.py +5 -4
  9. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/pyproject.toml +1 -1
  10. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/README.md +0 -0
  11. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/__init__.py +0 -0
  12. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/actions/__init__.py +0 -0
  13. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/actions/add_label.py +0 -0
  14. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/actions/add_to_bundle.py +0 -0
  15. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/actions/add_to_case.py +0 -0
  16. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/actions/change_field.py +0 -0
  17. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/actions/demote.py +0 -0
  18. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/actions/example_plugin.py +0 -0
  19. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/actions/prioritization.py +0 -0
  20. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/actions/promote.py +0 -0
  21. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/actions/remove_from_bundle.py +0 -0
  22. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/actions/remove_label.py +0 -0
  23. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/actions/transition.py +0 -0
  24. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/__init__.py +0 -0
  25. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/base.py +0 -0
  26. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/socket.py +0 -0
  27. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/__init__.py +0 -0
  28. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/action.py +0 -0
  29. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/analytic.py +0 -0
  30. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/auth.py +0 -0
  31. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/clue.py +0 -0
  32. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/configs.py +0 -0
  33. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/dossier.py +0 -0
  34. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/help.py +0 -0
  35. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/notebook.py +0 -0
  36. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/overview.py +0 -0
  37. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/search.py +0 -0
  38. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/template.py +0 -0
  39. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/tool.py +0 -0
  40. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/user.py +0 -0
  41. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/utils/__init__.py +0 -0
  42. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/utils/etag.py +0 -0
  43. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/utils/params.py +0 -0
  44. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/utils/permission_helper.py +0 -0
  45. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v1/view.py +0 -0
  46. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v2/__init__.py +0 -0
  47. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v2/case.py +0 -0
  48. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v2/fuzzy.py +0 -0
  49. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v2/ingest.py +0 -0
  50. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/api/v2/search.py +0 -0
  51. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/app.py +0 -0
  52. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/common/README.md +0 -0
  53. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/common/__init__.py +0 -0
  54. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/common/classification.py +0 -0
  55. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/common/classification.yml +0 -0
  56. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/common/exceptions.py +0 -0
  57. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/common/loader.py +0 -0
  58. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/common/logging/__init__.py +0 -0
  59. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/common/logging/audit.py +0 -0
  60. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/common/logging/format.py +0 -0
  61. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/common/net.py +0 -0
  62. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/common/net_static.py +0 -0
  63. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/common/random_user.py +0 -0
  64. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/common/swagger.py +0 -0
  65. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/config.py +0 -0
  66. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/cronjobs/__init__.py +0 -0
  67. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/cronjobs/action_queue_worker.py +0 -0
  68. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/cronjobs/correlation.py +0 -0
  69. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/cronjobs/view_cleanup.py +0 -0
  70. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/README.md +0 -0
  71. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/__init__.py +0 -0
  72. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/bulk.py +0 -0
  73. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/collection.py +0 -0
  74. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/constants.py +0 -0
  75. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/exceptions.py +0 -0
  76. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/howler_store.py +0 -0
  77. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/migrations/__init__.py +0 -0
  78. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/migrations/action_owner.py +0 -0
  79. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/migrations/base.py +0 -0
  80. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/migrations/fix_process.py +0 -0
  81. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/migrations/runner.py +0 -0
  82. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/operations.py +0 -0
  83. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/schemas.py +0 -0
  84. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/store.py +0 -0
  85. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/support/__init__.py +0 -0
  86. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/support/build.py +0 -0
  87. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/support/schemas.py +0 -0
  88. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/types.py +0 -0
  89. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/datastore/utils.py +0 -0
  90. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/error.py +0 -0
  91. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/external/README.md +0 -0
  92. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/external/__init__.py +0 -0
  93. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/external/check_duplicates.py +0 -0
  94. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/external/generate_mitre.py +0 -0
  95. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/external/generate_sigma_rules.py +0 -0
  96. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/external/generate_tlds.py +0 -0
  97. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/external/reindex_data.py +0 -0
  98. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/external/run_migrations.py +0 -0
  99. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/external/wipe_databases.py +0 -0
  100. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/gunicorn_config.py +0 -0
  101. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/healthz.py +0 -0
  102. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/helper/__init__.py +0 -0
  103. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/helper/azure.py +0 -0
  104. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/helper/discover.py +0 -0
  105. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/helper/hit.py +0 -0
  106. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/helper/oauth.py +0 -0
  107. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/helper/search.py +0 -0
  108. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/helper/workflow.py +0 -0
  109. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/helper/ws.py +0 -0
  110. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/README.md +0 -0
  111. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/__init__.py +0 -0
  112. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/base.py +0 -0
  113. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/charter.txt +0 -0
  114. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/constants.py +0 -0
  115. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/helper.py +0 -0
  116. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/howler_enum.py +0 -0
  117. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/mixins.py +0 -0
  118. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/__init__.py +0 -0
  119. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/action.py +0 -0
  120. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/analytic.py +0 -0
  121. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/assemblyline.py +0 -0
  122. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/aws.py +0 -0
  123. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/azure.py +0 -0
  124. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/case.py +0 -0
  125. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/cbs.py +0 -0
  126. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/clue.py +0 -0
  127. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/config.py +0 -0
  128. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/dossier.py +0 -0
  129. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/__init__.py +0 -0
  130. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/agent.py +0 -0
  131. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/autonomous_system.py +0 -0
  132. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/client.py +0 -0
  133. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/cloud.py +0 -0
  134. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/code_signature.py +0 -0
  135. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/container.py +0 -0
  136. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/dns.py +0 -0
  137. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/egress.py +0 -0
  138. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/elf.py +0 -0
  139. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/email.py +0 -0
  140. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/error.py +0 -0
  141. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/event.py +0 -0
  142. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/faas.py +0 -0
  143. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/file.py +0 -0
  144. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/geo.py +0 -0
  145. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/group.py +0 -0
  146. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/hash.py +0 -0
  147. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/host.py +0 -0
  148. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/http.py +0 -0
  149. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/ingress.py +0 -0
  150. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/interface.py +0 -0
  151. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/network.py +0 -0
  152. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/observer.py +0 -0
  153. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/organization.py +0 -0
  154. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/os.py +0 -0
  155. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/pe.py +0 -0
  156. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/process.py +0 -0
  157. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/registry.py +0 -0
  158. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/related.py +0 -0
  159. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/rule.py +0 -0
  160. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/server.py +0 -0
  161. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/threat.py +0 -0
  162. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/tls.py +0 -0
  163. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/url.py +0 -0
  164. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/user.py +0 -0
  165. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/user_agent.py +0 -0
  166. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ecs/vulnerability.py +0 -0
  167. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/gcp.py +0 -0
  168. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/hit.py +0 -0
  169. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/lead.py +0 -0
  170. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/localized_label.py +0 -0
  171. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/migration.py +0 -0
  172. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/overview.py +0 -0
  173. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/ownership.py +0 -0
  174. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/permission_request.py +0 -0
  175. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/pivot.py +0 -0
  176. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/record.py +0 -0
  177. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/template.py +0 -0
  178. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/user.py +0 -0
  179. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/models/view.py +0 -0
  180. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/random_data.py +0 -0
  181. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/odm/randomizer.py +0 -0
  182. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/patched.py +0 -0
  183. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/plugins/__init__.py +0 -0
  184. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/plugins/config.py +0 -0
  185. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/remote/__init__.py +0 -0
  186. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/remote/datatypes/README.md +0 -0
  187. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/remote/datatypes/__init__.py +0 -0
  188. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/remote/datatypes/counters.py +0 -0
  189. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/remote/datatypes/events.py +0 -0
  190. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/remote/datatypes/hash.py +0 -0
  191. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/remote/datatypes/lock.py +0 -0
  192. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/remote/datatypes/queues/__init__.py +0 -0
  193. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/remote/datatypes/queues/comms.py +0 -0
  194. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/remote/datatypes/queues/multi.py +0 -0
  195. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/remote/datatypes/queues/named.py +0 -0
  196. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/remote/datatypes/queues/priority.py +0 -0
  197. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/remote/datatypes/set.py +0 -0
  198. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/remote/datatypes/user_quota_tracker.py +0 -0
  199. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/security/__init__.py +0 -0
  200. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/security/login.py +0 -0
  201. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/security/socket.py +0 -0
  202. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/security/utils.py +0 -0
  203. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/__init__.py +0 -0
  204. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/action_service.py +0 -0
  205. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/analytic_service.py +0 -0
  206. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/auth_service.py +0 -0
  207. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/bundle_compat_service.py +0 -0
  208. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/comms_service.py +0 -0
  209. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/config_service.py +0 -0
  210. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/correlation_service.py +0 -0
  211. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/docs_service.py +0 -0
  212. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/dossier_service.py +0 -0
  213. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/event_service.py +0 -0
  214. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/fuzzy_service.py +0 -0
  215. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/jwt_service.py +0 -0
  216. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/lucene_service.py +0 -0
  217. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/notebook_service.py +0 -0
  218. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/overview_service.py +0 -0
  219. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/permission_service.py +0 -0
  220. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/search_service.py +0 -0
  221. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/template_service.py +0 -0
  222. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/user_service.py +0 -0
  223. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/services/viewer_service.py +0 -0
  224. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/telemetry.py +0 -0
  225. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/__init__.py +0 -0
  226. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/annotations.py +0 -0
  227. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/chunk.py +0 -0
  228. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/compat.py +0 -0
  229. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/constants.py +0 -0
  230. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/dict_utils.py +0 -0
  231. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/indexes.py +0 -0
  232. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/isotime.py +0 -0
  233. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/list_utils.py +0 -0
  234. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/lucene.py +0 -0
  235. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/net_utils.py +0 -0
  236. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/path.py +0 -0
  237. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/socket_utils.py +0 -0
  238. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/str_utils.py +0 -0
  239. {howler_api-4.1.0.dev1626 → howler_api-4.1.0.dev1635}/howler/utils/uid.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: howler-api
3
- Version: 4.1.0.dev1626
3
+ Version: 4.1.0.dev1635
4
4
  Summary: Howler - API server
5
5
  License: MIT
6
6
  Keywords: howler,alerting,gc,canada,cse-cst,cse,cst,cyber,cccs
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.11
18
18
  Classifier: Programming Language :: Python :: 3.12
19
19
  Classifier: Programming Language :: Python :: 3.13
20
20
  Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Python :: 3.15
21
22
  Classifier: Topic :: Software Development :: Libraries
22
23
  Requires-Dist: apscheduler (==3.11.3)
23
24
  Requires-Dist: authlib (>=1.6.0,<2.0.0)
@@ -27,7 +27,8 @@ from howler.datastore.exceptions import DataStoreException, VersionConflictExcep
27
27
  from howler.datastore.operations import OdmHelper, OdmUpdateOperation
28
28
  from howler.helper.workflow import WorkflowException
29
29
  from howler.odm.models.hit import Hit
30
- from howler.odm.models.howler_data import Comment, HitOperationType, HitStatusTransition
30
+ from howler.odm.models.howler_data import Comment, HitStatusTransition
31
+ from howler.odm.models.log import LogOperationType
31
32
  from howler.odm.models.user import User
32
33
  from howler.security.login import api_login
33
34
  from howler.security.utils import is_classification_accessible, validate_bulk_operation_targets
@@ -407,7 +408,7 @@ def update_hit(
407
408
  "explanation": f"Hit updated by {user.uname}\n\n" + "\n".join(explanation),
408
409
  "new_value": "N/A",
409
410
  "previous_value": "None",
410
- "type": HitOperationType.APPENDED,
411
+ "type": LogOperationType.APPENDED,
411
412
  "user": user.uname,
412
413
  },
413
414
  silent=True,
@@ -9,8 +9,13 @@ from pytz import timezone
9
9
  from howler.common.logging import get_logger
10
10
  from howler.config import DEBUG, config
11
11
  from howler.datastore.howler_store import HowlerDatastore
12
+ from howler.datastore.operations import OdmHelper
13
+ from howler.odm.models.case import CaseItemTypes
14
+ from howler.odm.models.hit import Hit
15
+ from howler.services import case_service
12
16
 
13
17
  logger = get_logger(__file__)
18
+ hit_helper = OdmHelper(Hit)
14
19
 
15
20
 
16
21
  def execute():
@@ -25,9 +30,7 @@ def execute():
25
30
 
26
31
  ds = datastore()
27
32
 
28
- ds.hit.delete_by_query(f"event.created:{{* TO {cutoff}}} OR howler.expiry:{{* TO now}}")
29
-
30
- ds.hit.commit()
33
+ _delete_matching_hits(ds, f"event.created:{{* TO {cutoff}}} OR howler.expiry:{{* TO now}}")
31
34
 
32
35
  logger.debug("Deletion complete")
33
36
 
@@ -82,8 +85,7 @@ def _execute_rules(ds: HowlerDatastore) -> None:
82
85
 
83
86
  try:
84
87
  count = ds.hit.count(combined_query, filters=None).get("count", -1)
85
- ds.hit.delete_by_query(combined_query)
86
- ds.hit.commit()
88
+ _delete_matching_hits(ds, combined_query)
87
89
  logger.debug("Retention rule '%s' complete", rule.name)
88
90
  result = {"rule": rule.name, "status": "ok", "deleted": count, "cutoff": cutoff}
89
91
  except Exception:
@@ -98,6 +100,26 @@ def _execute_rules(ds: HowlerDatastore) -> None:
98
100
  logger.info("Rule result: '%s'", result)
99
101
 
100
102
 
103
+ def _delete_matching_hits(ds: HowlerDatastore, query: str) -> None:
104
+ """Remove matching hits after cleaning their references from cases and hits."""
105
+ hit_ids = {hit.howler.id for hit in ds.hit.stream_search(query)}
106
+
107
+ if hit_ids:
108
+ id_query = " OR ".join(hit_ids)
109
+ for case in ds.case.stream_search(f"items.value:({id_query})"):
110
+ item_ids = [item.id for item in case.items if item.type == CaseItemTypes.HIT and item.value in hit_ids]
111
+ if item_ids:
112
+ case_service.remove_case_items(case, item_ids)
113
+
114
+ ds.hit.update_by_query(
115
+ f"howler.related:({id_query})",
116
+ [hit_helper.list_remove("howler.related", hit_id, silent=True) for hit_id in hit_ids],
117
+ )
118
+
119
+ ds.hit.delete_by_query(query)
120
+ ds.hit.commit()
121
+
122
+
101
123
  def _remove_analytics_without_hits(ds: HowlerDatastore):
102
124
  matched_analytics = _find_analytics_with_hits(ds)
103
125
 
@@ -1,10 +1,10 @@
1
1
  # mypy: ignore-errors
2
2
 
3
3
  from howler import odm
4
- from howler.common.exceptions import HowlerValueError
5
4
  from howler.common.logging import get_logger
6
5
  from howler.odm.howler_enum import HowlerEnum
7
6
  from howler.odm.mixins import DatastoreMixin
7
+ from howler.odm.models.log import Log
8
8
  from howler.odm.models.record import Record
9
9
 
10
10
  logger = get_logger(__file__)
@@ -30,26 +30,6 @@ class Comment(odm.Model):
30
30
  )
31
31
 
32
32
 
33
- @odm.model(index=True, store=True, description="Log definition.")
34
- class Log(odm.Model):
35
- timestamp = odm.Date(description="Timestamp at which the Log event took place.")
36
- key = odm.Optional(odm.Keyword(description="The key whose value changed."))
37
- explanation = odm.Optional(odm.Text(description="A manual description of the changes made."))
38
- new_value = odm.Optional(odm.Keyword(description="The value the key is changing to."))
39
- previous_value = odm.Optional(odm.Keyword(description="The value the key is changing from."))
40
- user = odm.Keyword(description="User ID who created the log event.")
41
-
42
- def __init__(self, data: dict = None, *args, **kwargs):
43
- if "explanation" not in data:
44
- required_keys = {"key", "new_value", "previous_value"}
45
- if required_keys.intersection(set(data.keys())) != required_keys:
46
- raise HowlerValueError(
47
- f"If no explanation provided, you must provide the following values: {','.join(required_keys)}"
48
- )
49
-
50
- super().__init__(data, *args, **kwargs)
51
-
52
-
53
33
  DEFAULT_LABELS = {"assignments": [], "generic": []}
54
34
 
55
35
 
@@ -3,10 +3,10 @@ from datetime import datetime
3
3
  from typing import Optional
4
4
 
5
5
  from howler import odm
6
- from howler.common.exceptions import HowlerValueError
7
6
  from howler.odm.constants import Status
8
7
  from howler.odm.howler_enum import HowlerEnum
9
8
  from howler.odm.models.lead import Lead
9
+ from howler.odm.models.log import Log
10
10
 
11
11
 
12
12
  class Scrutiny(str, HowlerEnum):
@@ -31,12 +31,6 @@ class HitStatusTransition(str, HowlerEnum):
31
31
  DEMOTE = "demote"
32
32
 
33
33
 
34
- class HitOperationType(str, HowlerEnum):
35
- APPENDED = "appended"
36
- REMOVED = "removed"
37
- SET = "set"
38
-
39
-
40
34
  class Escalation(str, HowlerEnum):
41
35
  MISS = "miss"
42
36
  HIT = "hit"
@@ -107,28 +101,6 @@ class Comment(odm.Model):
107
101
  )
108
102
 
109
103
 
110
- @odm.model(index=True, store=True, description="Log definition.")
111
- class Log(odm.Model):
112
- timestamp = odm.Date(description="Timestamp at which the Log event took place.")
113
- key = odm.Optional(odm.Keyword(description="The key whose value changed."))
114
- explanation = odm.Optional(odm.Text(description="A manual description of the changes made."))
115
- previous_version = odm.Optional(odm.Keyword(description="The version this action was applied to."))
116
- new_value = odm.Optional(odm.Keyword(description="The value the key is changing to."))
117
- type = odm.Optional(odm.Enum(values=HitOperationType, description="The operation performed on the value."))
118
- previous_value = odm.Optional(odm.Keyword(description="The value the key is changing from."))
119
- user = odm.Keyword(description="User ID who created the log event.")
120
-
121
- def __init__(self, data: dict = None, *args, **kwargs):
122
- if "explanation" not in data:
123
- required_keys = {"key", "new_value", "type", "previous_value"}
124
- if required_keys.intersection(set(data.keys())) != required_keys:
125
- raise HowlerValueError(
126
- f"If no explanation provided, you must provide the following values: {','.join(required_keys)}"
127
- )
128
-
129
- super().__init__(data, *args, **kwargs)
130
-
131
-
132
104
  @odm.model(index=True, store=True, description="Hit outline header.")
133
105
  class Header(odm.Model):
134
106
  threat: str | None = odm.Optional(odm.Keyword(description="The IP of the threat."))
@@ -0,0 +1,31 @@
1
+ from howler import odm
2
+ from howler.common.exceptions import HowlerValueError
3
+ from howler.odm.howler_enum import HowlerEnum
4
+
5
+
6
+ class LogOperationType(str, HowlerEnum):
7
+ APPENDED = "appended"
8
+ REMOVED = "removed"
9
+ SET = "set"
10
+
11
+
12
+ @odm.model(index=True, store=True, description="Log definition.") # noqa: F821
13
+ class Log(odm.Model):
14
+ timestamp = odm.Date(description="Timestamp at which the Log event took place.")
15
+ key = odm.Optional(odm.Keyword(description="The key whose value changed."))
16
+ explanation = odm.Optional(odm.Text(description="A manual description of the changes made."))
17
+ previous_version = odm.Optional(odm.Keyword(description="The version this action was applied to."))
18
+ new_value = odm.Optional(odm.Keyword(description="The value the key is changing to."))
19
+ type = odm.Optional(odm.Enum(values=LogOperationType, description="The operation performed on the value."))
20
+ previous_value = odm.Optional(odm.Keyword(description="The value the key is changing from."))
21
+ user = odm.Keyword(description="User ID who created the log event.")
22
+
23
+ def __init__(self, data: dict = None, *args, **kwargs):
24
+ if "explanation" not in data:
25
+ required_keys = {"key", "new_value", "previous_value"}
26
+ if required_keys.intersection(set(data.keys())) != required_keys:
27
+ raise HowlerValueError(
28
+ f"If no explanation provided, you must provide the following values: {','.join(required_keys)}"
29
+ )
30
+
31
+ super().__init__(data, *args, **kwargs)
@@ -26,6 +26,7 @@ from howler.odm.models.case import Case, CaseItem, CaseItemTypes, CaseLog, CaseR
26
26
  from howler.odm.models.ecs.related import Related
27
27
  from howler.odm.models.event import Event
28
28
  from howler.odm.models.hit import Hit
29
+ from howler.odm.models.log import Log
29
30
  from howler.odm.models.user import User
30
31
  from howler.security.utils import is_classification_accessible
31
32
  from howler.services import comms_service, event_service, hit_service
@@ -788,7 +789,7 @@ def remove_case_items( # noqa: C901
788
789
  case.items = [item for item in case.items if item.id not in ids_to_remove]
789
790
 
790
791
  for backing_obj, backing_obj_version in backing_objs:
791
- remove_backreference(backing_obj, case.case_id)
792
+ remove_backreference(backing_obj, case.case_id, user=user)
792
793
  backing_obj.save(version=backing_obj_version)
793
794
 
794
795
  recompute_case_metadata(case)
@@ -845,7 +846,7 @@ def append_hit(
845
846
 
846
847
  case.items.append(item)
847
848
 
848
- add_backreference(hit, case.case_id)
849
+ add_backreference(hit, case.case_id, user=user)
849
850
  hit.save(version=hit_version)
850
851
 
851
852
  recompute_case_metadata(case)
@@ -889,7 +890,7 @@ def append_event(
889
890
 
890
891
  case.items.append(item)
891
892
 
892
- add_backreference(event, case.case_id)
893
+ add_backreference(event, case.case_id, user=user)
893
894
  event.save(version=event_version)
894
895
 
895
896
  recompute_case_metadata(case)
@@ -996,7 +997,11 @@ def recompute_case_metadata(case: Case) -> None: # noqa: C901
996
997
  case.indicators = sorted(indicators)
997
998
 
998
999
 
999
- def add_backreference(backing_obj: Hit | Event | None, case_id: str) -> bool:
1000
+ def add_backreference(
1001
+ backing_obj: Hit | Event | None,
1002
+ case_id: str,
1003
+ user: User | None = None,
1004
+ ) -> bool:
1000
1005
  """Add a back-reference from a hit or event to a case, in memory only.
1001
1006
 
1002
1007
  Records the case ID in the backing object's ``howler.related`` list so
@@ -1023,12 +1028,23 @@ def add_backreference(backing_obj: Hit | Event | None, case_id: str) -> bool:
1023
1028
  return False
1024
1029
 
1025
1030
  backing_obj.howler.related.append(case_id)
1031
+ backing_obj.howler.log.append(
1032
+ Log(
1033
+ {
1034
+ "timestamp": "NOW",
1035
+ "explanation": f"Added to case {case_id}",
1036
+ "user": user.uname if user else "system",
1037
+ }
1038
+ )
1039
+ )
1040
+
1026
1041
  return True
1027
1042
 
1028
1043
 
1029
1044
  def remove_backreference(
1030
1045
  backing_obj: Hit | Event | None,
1031
1046
  case_id: str,
1047
+ user: User | None = None,
1032
1048
  ):
1033
1049
  """Remove a back-reference from a hit or event to a case, in memory only.
1034
1050
 
@@ -1052,6 +1068,16 @@ def remove_backreference(
1052
1068
  if case_id in backing_obj.howler.related:
1053
1069
  backing_obj.howler.related.remove(case_id)
1054
1070
 
1071
+ backing_obj.howler.log.append(
1072
+ Log(
1073
+ {
1074
+ "timestamp": "NOW",
1075
+ "explanation": f"Removed from case {case_id}",
1076
+ "user": user.uname if user else "system",
1077
+ }
1078
+ )
1079
+ )
1080
+
1055
1081
 
1056
1082
  def rename_case_item(
1057
1083
  case: str | Case | None,
@@ -29,7 +29,8 @@ from howler.helper.hit import (
29
29
  from howler.helper.workflow import Transition, Workflow
30
30
  from howler.odm.models.ecs.event import ECSEvent
31
31
  from howler.odm.models.hit import Hit
32
- from howler.odm.models.howler_data import HitOperationType, HitStatusTransition, Log, Status
32
+ from howler.odm.models.howler_data import HitStatusTransition, Status
33
+ from howler.odm.models.log import Log, LogOperationType
33
34
  from howler.odm.models.user import User
34
35
  from howler.security.utils import is_classification_accessible
35
36
  from howler.services import action_service, analytic_service, dossier_service, overview_service, template_service
@@ -625,16 +626,16 @@ def _update_hit(
625
626
 
626
627
  if is_list:
627
628
  operation_type = (
628
- HitOperationType.APPENDED
629
+ LogOperationType.APPENDED
629
630
  if operation.operation
630
631
  in (
631
632
  ESCollection.UPDATE_APPEND,
632
633
  ESCollection.UPDATE_APPEND_IF_MISSING,
633
634
  )
634
- else HitOperationType.REMOVED
635
+ else LogOperationType.REMOVED
635
636
  )
636
637
  else:
637
- operation_type = HitOperationType.SET
638
+ operation_type = LogOperationType.SET
638
639
 
639
640
  logger.debug("%s - %s - %s -> %s", hit_id, operation.key, previous_value, operation.value)
640
641
  final_operations.append(operation)
@@ -244,7 +244,7 @@ suppress-none-returning = true
244
244
  [tool.poetry]
245
245
  package-mode = true
246
246
  name = "howler-api"
247
- version = "4.1.0.dev1626"
247
+ version = "4.1.0.dev1635"
248
248
  description = "Howler - API server"
249
249
  authors = [
250
250
  "Canadian Centre for Cyber Security <howler@cyber.gc.ca>",