howler-api 4.0.0.dev1283__tar.gz → 4.0.0.dev1297__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 (225) hide show
  1. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/PKG-INFO +1 -1
  2. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/common/loader.py +1 -0
  3. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/collection.py +2 -2
  4. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/howler_data.py +15 -15
  5. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/fuzzy_service.py +4 -4
  6. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/hit_service.py +12 -0
  7. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/search_service.py +4 -47
  8. howler_api-4.0.0.dev1297/howler/utils/indexes.py +56 -0
  9. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/pyproject.toml +1 -1
  10. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/README.md +0 -0
  11. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/__init__.py +0 -0
  12. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/actions/__init__.py +0 -0
  13. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/actions/add_label.py +0 -0
  14. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/actions/add_to_bundle.py +0 -0
  15. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/actions/add_to_case.py +0 -0
  16. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/actions/change_field.py +0 -0
  17. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/actions/demote.py +0 -0
  18. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/actions/example_plugin.py +0 -0
  19. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/actions/prioritization.py +0 -0
  20. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/actions/promote.py +0 -0
  21. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/actions/remove_from_bundle.py +0 -0
  22. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/actions/remove_label.py +0 -0
  23. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/actions/transition.py +0 -0
  24. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/__init__.py +0 -0
  25. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/base.py +0 -0
  26. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/socket.py +0 -0
  27. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/__init__.py +0 -0
  28. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/action.py +0 -0
  29. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/analytic.py +0 -0
  30. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/auth.py +0 -0
  31. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/clue.py +0 -0
  32. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/configs.py +0 -0
  33. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/dossier.py +0 -0
  34. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/help.py +0 -0
  35. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/hit.py +0 -0
  36. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/notebook.py +0 -0
  37. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/overview.py +0 -0
  38. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/search.py +0 -0
  39. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/template.py +0 -0
  40. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/tool.py +0 -0
  41. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/user.py +0 -0
  42. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/utils/__init__.py +0 -0
  43. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/utils/etag.py +0 -0
  44. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/utils/params.py +0 -0
  45. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v1/view.py +0 -0
  46. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v2/__init__.py +0 -0
  47. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v2/case.py +0 -0
  48. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v2/fuzzy.py +0 -0
  49. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v2/ingest.py +0 -0
  50. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/api/v2/search.py +0 -0
  51. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/app.py +0 -0
  52. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/common/README.md +0 -0
  53. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/common/__init__.py +0 -0
  54. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/common/classification.py +0 -0
  55. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/common/classification.yml +0 -0
  56. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/common/exceptions.py +0 -0
  57. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/common/logging/__init__.py +0 -0
  58. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/common/logging/audit.py +0 -0
  59. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/common/logging/format.py +0 -0
  60. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/common/net.py +0 -0
  61. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/common/net_static.py +0 -0
  62. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/common/random_user.py +0 -0
  63. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/common/swagger.py +0 -0
  64. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/config.py +0 -0
  65. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/cronjobs/__init__.py +0 -0
  66. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/cronjobs/action_queue_worker.py +0 -0
  67. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/cronjobs/correlation.py +0 -0
  68. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/cronjobs/retention.py +0 -0
  69. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/cronjobs/view_cleanup.py +0 -0
  70. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/README.md +0 -0
  71. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/__init__.py +0 -0
  72. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/bulk.py +0 -0
  73. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/constants.py +0 -0
  74. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/exceptions.py +0 -0
  75. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/howler_store.py +0 -0
  76. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/migrations/fix_process.py +0 -0
  77. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/operations.py +0 -0
  78. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/schemas.py +0 -0
  79. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/store.py +0 -0
  80. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/support/__init__.py +0 -0
  81. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/support/build.py +0 -0
  82. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/support/schemas.py +0 -0
  83. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/datastore/types.py +0 -0
  84. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/error.py +0 -0
  85. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/external/README.md +0 -0
  86. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/external/__init__.py +0 -0
  87. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/external/generate_mitre.py +0 -0
  88. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/external/generate_sigma_rules.py +0 -0
  89. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/external/generate_tlds.py +0 -0
  90. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/external/reindex_data.py +0 -0
  91. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/external/wipe_databases.py +0 -0
  92. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/gunicorn_config.py +0 -0
  93. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/healthz.py +0 -0
  94. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/helper/__init__.py +0 -0
  95. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/helper/azure.py +0 -0
  96. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/helper/discover.py +0 -0
  97. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/helper/hit.py +0 -0
  98. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/helper/oauth.py +0 -0
  99. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/helper/search.py +0 -0
  100. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/helper/workflow.py +0 -0
  101. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/helper/ws.py +0 -0
  102. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/README.md +0 -0
  103. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/__init__.py +0 -0
  104. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/base.py +0 -0
  105. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/charter.txt +0 -0
  106. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/constants.py +0 -0
  107. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/helper.py +0 -0
  108. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/howler_enum.py +0 -0
  109. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/mixins.py +0 -0
  110. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/__init__.py +0 -0
  111. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/action.py +0 -0
  112. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/analytic.py +0 -0
  113. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/assemblyline.py +0 -0
  114. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/aws.py +0 -0
  115. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/azure.py +0 -0
  116. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/case.py +0 -0
  117. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/cbs.py +0 -0
  118. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/clue.py +0 -0
  119. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/config.py +0 -0
  120. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/dossier.py +0 -0
  121. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/__init__.py +0 -0
  122. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/agent.py +0 -0
  123. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/autonomous_system.py +0 -0
  124. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/client.py +0 -0
  125. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/cloud.py +0 -0
  126. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/code_signature.py +0 -0
  127. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/container.py +0 -0
  128. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/dns.py +0 -0
  129. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/egress.py +0 -0
  130. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/elf.py +0 -0
  131. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/email.py +0 -0
  132. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/error.py +0 -0
  133. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/event.py +0 -0
  134. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/faas.py +0 -0
  135. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/file.py +0 -0
  136. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/geo.py +0 -0
  137. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/group.py +0 -0
  138. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/hash.py +0 -0
  139. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/host.py +0 -0
  140. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/http.py +0 -0
  141. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/ingress.py +0 -0
  142. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/interface.py +0 -0
  143. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/network.py +0 -0
  144. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/observer.py +0 -0
  145. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/organization.py +0 -0
  146. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/os.py +0 -0
  147. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/pe.py +0 -0
  148. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/process.py +0 -0
  149. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/registry.py +0 -0
  150. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/related.py +0 -0
  151. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/rule.py +0 -0
  152. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/server.py +0 -0
  153. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/threat.py +0 -0
  154. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/tls.py +0 -0
  155. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/url.py +0 -0
  156. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/user.py +0 -0
  157. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/user_agent.py +0 -0
  158. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/ecs/vulnerability.py +0 -0
  159. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/event.py +0 -0
  160. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/gcp.py +0 -0
  161. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/hit.py +0 -0
  162. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/lead.py +0 -0
  163. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/localized_label.py +0 -0
  164. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/overview.py +0 -0
  165. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/pivot.py +0 -0
  166. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/record.py +0 -0
  167. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/template.py +0 -0
  168. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/user.py +0 -0
  169. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/models/view.py +0 -0
  170. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/random_data.py +0 -0
  171. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/odm/randomizer.py +0 -0
  172. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/patched.py +0 -0
  173. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/plugins/__init__.py +0 -0
  174. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/plugins/config.py +0 -0
  175. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/remote/__init__.py +0 -0
  176. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/remote/datatypes/README.md +0 -0
  177. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/remote/datatypes/__init__.py +0 -0
  178. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/remote/datatypes/counters.py +0 -0
  179. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/remote/datatypes/events.py +0 -0
  180. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/remote/datatypes/hash.py +0 -0
  181. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/remote/datatypes/lock.py +0 -0
  182. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/remote/datatypes/queues/__init__.py +0 -0
  183. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/remote/datatypes/queues/comms.py +0 -0
  184. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/remote/datatypes/queues/multi.py +0 -0
  185. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/remote/datatypes/queues/named.py +0 -0
  186. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/remote/datatypes/queues/priority.py +0 -0
  187. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/remote/datatypes/set.py +0 -0
  188. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/remote/datatypes/user_quota_tracker.py +0 -0
  189. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/security/__init__.py +0 -0
  190. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/security/socket.py +0 -0
  191. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/security/utils.py +0 -0
  192. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/__init__.py +0 -0
  193. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/action_service.py +0 -0
  194. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/analytic_service.py +0 -0
  195. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/auth_service.py +0 -0
  196. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/bundle_compat_service.py +0 -0
  197. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/case_service.py +0 -0
  198. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/comms_service.py +0 -0
  199. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/config_service.py +0 -0
  200. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/correlation_service.py +0 -0
  201. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/docs_service.py +0 -0
  202. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/dossier_service.py +0 -0
  203. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/event_service.py +0 -0
  204. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/jwt_service.py +0 -0
  205. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/lucene_service.py +0 -0
  206. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/notebook_service.py +0 -0
  207. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/overview_service.py +0 -0
  208. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/template_service.py +0 -0
  209. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/user_service.py +0 -0
  210. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/services/viewer_service.py +0 -0
  211. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/telemetry.py +0 -0
  212. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/utils/__init__.py +0 -0
  213. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/utils/annotations.py +0 -0
  214. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/utils/chunk.py +0 -0
  215. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/utils/compat.py +0 -0
  216. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/utils/constants.py +0 -0
  217. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/utils/dict_utils.py +0 -0
  218. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/utils/isotime.py +0 -0
  219. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/utils/list_utils.py +0 -0
  220. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/utils/lucene.py +0 -0
  221. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/utils/net_utils.py +0 -0
  222. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/utils/path.py +0 -0
  223. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/utils/socket_utils.py +0 -0
  224. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/howler/utils/str_utils.py +0 -0
  225. {howler_api-4.0.0.dev1283 → howler_api-4.0.0.dev1297}/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.dev1283
3
+ Version: 4.0.0.dev1297
4
4
  Summary: Howler - API server
5
5
  License: MIT
6
6
  Keywords: howler,alerting,gc,canada,cse-cst,cse,cst,cyber,cccs
@@ -14,6 +14,7 @@ if TYPE_CHECKING:
14
14
 
15
15
 
16
16
  APP_NAME = os.environ.get("APP_NAME", "howler")
17
+ DATASTORE_INDEX_PREFIX = os.environ.get("HWL_DATASTORE_INDEX_PREFIX", APP_NAME)
17
18
  APP_PREFIX = os.environ.get("APP_PREFIX", "hwl")
18
19
  USER_TYPES = {"admin", "user", "automation_basic", "automation_advanced", "actionrunner_basic", "actionrunner_advanced"}
19
20
 
@@ -20,7 +20,7 @@ from opentelemetry import trace
20
20
 
21
21
  from howler import odm
22
22
  from howler.common.exceptions import HowlerRuntimeError, HowlerValueError, NonRecoverableError
23
- from howler.common.loader import APP_NAME
23
+ from howler.common.loader import DATASTORE_INDEX_PREFIX
24
24
  from howler.common.logging.format import HWL_DATE_FORMAT, HWL_LOG_FORMAT
25
25
  from howler.datastore.constants import BACK_MAPPING, TYPE_MAPPING
26
26
  from howler.datastore.exceptions import (
@@ -229,7 +229,7 @@ class ESCollection(Generic[ModelType]):
229
229
  self._index_list: list[str] = []
230
230
 
231
231
  self.datastore = datastore
232
- self.name = f"{APP_NAME}-{name}"
232
+ self.name = f"{DATASTORE_INDEX_PREFIX}-{name}"
233
233
  self.ilm_config = ilm_config
234
234
  self.index_name = f"{self.name}_hot"
235
235
  self.model_class = model_class
@@ -131,17 +131,17 @@ class Log(odm.Model):
131
131
 
132
132
  @odm.model(index=True, store=True, description="Hit outline header.")
133
133
  class Header(odm.Model):
134
- threat: Optional[str] = odm.Optional(odm.Keyword(description="The IP of the threat."))
135
- target: Optional[str] = odm.Optional(odm.Keyword(description="The target of the hit."))
134
+ threat: str | None = odm.Optional(odm.Keyword(description="The IP of the threat."))
135
+ target: str | None = odm.Optional(odm.Keyword(description="The target of the hit."))
136
136
  indicators: list[str] = odm.List(odm.Keyword(description="Indicators of the hit."), default=[])
137
- summary: Optional[str] = odm.Optional(odm.Keyword(description="Summary of the hit."))
137
+ summary: str | None = odm.Optional(odm.Keyword(description="Summary of the hit."))
138
138
 
139
139
 
140
140
  @odm.model(index=True, store=True, description="Fields describing the location where this alert has been retained.")
141
141
  class Incident(odm.Model):
142
142
  platform: str = odm.Keyword(description="The name of the platform for this incident.")
143
- incident_id: Optional[str] = odm.Keyword(description="The ID of the incident.", optional=True)
144
- url: Optional[str] = odm.Keyword(description="The url where the incident can be found.", optional=True)
143
+ incident_id: str | None = odm.Keyword(description="The ID of the incident.", optional=True)
144
+ url: str | None = odm.Keyword(description="The url where the incident can be found.", optional=True)
145
145
 
146
146
 
147
147
  @odm.model(index=True, store=True, description="Labels for the hit")
@@ -177,7 +177,7 @@ DEFAULT_ASSIGNMENT = "unassigned"
177
177
  class HowlerData(odm.Model):
178
178
  id: str = odm.UUID(description="A UUID for this hit.")
179
179
  analytic: str = odm.CaseInsensitiveKeyword(description="Title of the analytic.")
180
- assignment: Optional[str] = odm.Keyword(
180
+ assignment: str = odm.Keyword(
181
181
  description="Unique identifier of the assigned user.",
182
182
  default=DEFAULT_ASSIGNMENT,
183
183
  )
@@ -191,7 +191,7 @@ class HowlerData(odm.Model):
191
191
  default=[],
192
192
  description="A list of links associated with this hit.",
193
193
  )
194
- detection: Optional[str] = odm.Optional(
194
+ detection: str | None = odm.Optional(
195
195
  odm.CaseInsensitiveKeyword(description="The detection that produced this hit.")
196
196
  )
197
197
  hash: str = odm.HowlerHash(
@@ -219,13 +219,13 @@ class HowlerData(odm.Model):
219
219
  score: Optional[float] = odm.Optional(
220
220
  odm.Float(description="A score assigned by an enrichment to help prioritize triage.", default=0)
221
221
  )
222
- status = odm.Enum(values=Status, default=Status.OPEN, description="Status of the hit.")
223
- scrutiny = odm.Enum(
222
+ status: str = odm.Enum(values=Status, default=Status.OPEN, description="Status of the hit.")
223
+ scrutiny: str = odm.Enum(
224
224
  values=Scrutiny,
225
225
  default=Scrutiny.UNSEEN,
226
226
  description="Level of scrutiny done to this hit.",
227
227
  )
228
- escalation = odm.Enum(
228
+ escalation: str = odm.Enum(
229
229
  values=Escalation,
230
230
  default=Escalation.HIT,
231
231
  description="Level of escalation of this hit.",
@@ -235,8 +235,8 @@ class HowlerData(odm.Model):
235
235
  description="User selected time for hit expiry",
236
236
  )
237
237
  )
238
- assessment: Optional[str] = odm.Optional(odm.Enum(values=Assessment, description="Assessment of the hit."))
239
- rationale: Optional[str] = odm.Optional(
238
+ assessment: str | None = odm.Optional(odm.Enum(values=Assessment, description="Assessment of the hit."))
239
+ rationale: str | None = odm.Optional(
240
240
  odm.Keyword(
241
241
  description=(
242
242
  "The rationale behind the hit assessment. Allows it to be understood and verified by other analysts."
@@ -254,9 +254,9 @@ class HowlerData(odm.Model):
254
254
  default=[],
255
255
  description="A list of changes to the hit with timestamps and attribution.",
256
256
  )
257
- monitored: Optional[str] = odm.Optional(odm.Keyword(description="Link to the incident monitoring dashboard."))
258
- reported: Optional[str] = odm.Optional(odm.Keyword(description="Link to the incident report."))
259
- mitigated: Optional[str] = odm.Optional(odm.Keyword(description="Link to the mitigation record (tool dependent)."))
257
+ monitored: str | None = odm.Optional(odm.Keyword(description="Link to the incident monitoring dashboard."))
258
+ reported: str | None = odm.Optional(odm.Keyword(description="Link to the incident report."))
259
+ mitigated: str | None = odm.Optional(odm.Keyword(description="Link to the mitigation record (tool dependent)."))
260
260
  outline: Optional[Header] = odm.Optional(odm.Compound(Header), description="The user specified header of the hit")
261
261
  incidents: list[Incident] = odm.List(
262
262
  odm.Compound(Incident), default=[], description="Fields describing an incident associated with this alert."
@@ -8,7 +8,7 @@ import elasticsearch
8
8
  from elasticsearch import Elasticsearch
9
9
 
10
10
  from howler import odm
11
- from howler.common.loader import APP_NAME, datastore
11
+ from howler.common.loader import datastore
12
12
  from howler.common.logging import get_logger
13
13
  from howler.datastore.exceptions import SearchException, SearchRetryException
14
14
  from howler.datastore.types import SearchResult
@@ -25,7 +25,7 @@ from howler.odm.base import (
25
25
  Text,
26
26
  _Field,
27
27
  )
28
- from howler.services.search_service import _normalize_indexes
28
+ from howler.utils.indexes import get_logical_index_name, normalize_indexes
29
29
  from howler.utils.str_utils import sanitize_lucene_query
30
30
 
31
31
  DEFAULT_OFFSET = 0
@@ -369,7 +369,7 @@ def fuzzy_search(
369
369
  raise SearchException(f"Invalid index for fuzzy search: {idx}")
370
370
 
371
371
  client: Elasticsearch = datastore().ds.client
372
- parsed_indexes = _normalize_indexes(indexes)
372
+ parsed_indexes = normalize_indexes(indexes)
373
373
 
374
374
  query_body = build_fuzzy_query(query, indexes, filters, access_control)
375
375
 
@@ -420,7 +420,7 @@ def _format_items_with_score(hits: list[dict[str, Any]]) -> list[dict[str, Any]]
420
420
  if source:
421
421
  raw_index = hit.get("_index", None)
422
422
  if raw_index:
423
- source["__index"] = raw_index.replace(f"{APP_NAME}-", "").replace("_hot", "")
423
+ source["__index"] = get_logical_index_name(raw_index)
424
424
  source["_score"] = hit.get("_score", 0)
425
425
  items.append(source)
426
426
  return items
@@ -317,6 +317,18 @@ def convert_hit( # noqa: C901
317
317
  "See howler's documentation for more information."
318
318
  )
319
319
 
320
+ if odm.howler.assessment:
321
+ target_escalation = AssessmentEscalationMap[odm.howler.assessment]
322
+ if odm.howler.escalation != target_escalation:
323
+ warnings.append(
324
+ f"Hits with assessment {odm.howler.assessment} must also have escalation set to {target_escalation}."
325
+ )
326
+ odm.howler.escalation = str(target_escalation)
327
+
328
+ if odm.howler.escalation in [Escalation.MISS, Escalation.EVIDENCE] and odm.howler.status != Status.RESOLVED:
329
+ warnings.append("Hits with escalation miss or evidence must also have their status set to resolved.")
330
+ odm.howler.status = Status.RESOLVED.value
331
+
320
332
  if odm.event:
321
333
  odm.event.id = odm.howler.id
322
334
  if not odm.event.created:
@@ -5,7 +5,7 @@ from typing import Any
5
5
  import elasticsearch
6
6
  from elasticsearch import Elasticsearch
7
7
 
8
- from howler.common.loader import APP_NAME, datastore
8
+ from howler.common.loader import datastore
9
9
  from howler.common.logging import get_logger
10
10
  from howler.datastore.collection import parse_sort
11
11
  from howler.datastore.exceptions import SearchException, SearchRetryException
@@ -13,6 +13,7 @@ from howler.datastore.types import SearchResult
13
13
  from howler.helper.search import get_collection, has_access_control
14
14
  from howler.odm.models.user import User
15
15
  from howler.services import case_service
16
+ from howler.utils.indexes import get_logical_index_name, normalize_indexes
16
17
 
17
18
  DEFAULT_OFFSET = 0
18
19
  DEFAULT_ROW_SIZE = 25
@@ -23,50 +24,6 @@ SCROLL_TIMEOUT = "5m"
23
24
  logger = get_logger(__file__)
24
25
 
25
26
 
26
- def _normalize_indexes(indexes: str | list[str]) -> str:
27
- """Normalizes Elasticsearch index names into a comma-separated string.
28
-
29
- Parses the input indexes and applies naming conventions. Special patterns like
30
- wildcards, exclusions, and explicitly formatted indexes are preserved as-is.
31
- Regular indexes are formatted with the APP_NAME prefix and '_hot' suffix.
32
-
33
- Args:
34
- indexes: A comma-separated string or list of index names to normalize.
35
-
36
- Returns:
37
- A comma-separated string of normalized index names ready for Elasticsearch queries.
38
-
39
- Raises:
40
- SearchException: If no valid indexes are provided after parsing and stripping whitespace.
41
-
42
- Examples:
43
- >>> _normalize_indexes("logs,metrics")
44
- "howler-logs_hot,howler-metrics_hot"
45
-
46
- >>> _normalize_indexes(["*", "custom-index"])
47
- "*,custom-index"
48
-
49
- >>> _normalize_indexes("alerts, events")
50
- "howler-alerts_hot,howler-events_hot"
51
- """
52
- if isinstance(indexes, str):
53
- parsed_indexes = [item.strip() for item in indexes.split(",") if item.strip()]
54
- else:
55
- parsed_indexes = [item.strip() for item in indexes if item.strip()]
56
-
57
- if not parsed_indexes:
58
- raise SearchException("No indexes were provided.")
59
-
60
- normalized_indexes: list[str] = []
61
- for index in parsed_indexes:
62
- if index in {"*", "_all"} or "-" in index or "*" in index:
63
- normalized_indexes.append(index)
64
- else:
65
- normalized_indexes.append(f"{APP_NAME}-{index}")
66
-
67
- return ",".join(normalized_indexes)
68
-
69
-
70
27
  def _format_items(hits: list[dict[str, Any]], user_classification: str | None) -> list[dict[str, Any]]:
71
28
  """Formats Elasticsearch search hits into a standardized item format.
72
29
 
@@ -86,7 +43,7 @@ def _format_items(hits: list[dict[str, Any]], user_classification: str | None) -
86
43
  raw_index = hit.get("_index", None)
87
44
 
88
45
  if raw_index:
89
- source["__index"] = raw_index.replace(f"{APP_NAME}-", "").replace("_hot", "")
46
+ source["__index"] = get_logical_index_name(raw_index)
90
47
 
91
48
  if source.get("__index") == "case" and user_classification:
92
49
  case_service.filter_case_items_by_classification(source, user_classification)
@@ -137,7 +94,7 @@ def search( # noqa: C901
137
94
  del metadata
138
95
 
139
96
  client: Elasticsearch = datastore().ds.client
140
- parsed_indexes = _normalize_indexes(indexes)
97
+ parsed_indexes = normalize_indexes(indexes)
141
98
 
142
99
  if filters is None:
143
100
  parsed_filters: list[str] = []
@@ -0,0 +1,56 @@
1
+ from howler.common.loader import APP_NAME, DATASTORE_INDEX_PREFIX
2
+ from howler.datastore.exceptions import SearchException
3
+
4
+
5
+ def normalize_indexes(indexes: str | list[str]) -> str:
6
+ """Normalizes Elasticsearch index names into a comma-separated string.
7
+
8
+ Parses the input indexes and applies naming conventions. Special patterns like
9
+ wildcards, exclusions, and explicitly formatted indexes are preserved as-is.
10
+ Regular indexes are formatted with the datastore index prefix and '_hot' suffix.
11
+
12
+ Args:
13
+ indexes: A comma-separated string or list of index names to normalize.
14
+
15
+ Returns:
16
+ A comma-separated string of normalized index names ready for Elasticsearch queries.
17
+
18
+ Raises:
19
+ SearchException: If no valid indexes are provided after parsing and stripping whitespace.
20
+
21
+ Examples:
22
+ >>> normalize_indexes("logs,metrics")
23
+ "howler-logs_hot,howler-metrics_hot"
24
+
25
+ >>> normalize_indexes(["*", "custom-index"])
26
+ "*,custom-index"
27
+
28
+ >>> normalize_indexes("alerts, events")
29
+ "howler-alerts_hot,howler-events_hot"
30
+ """
31
+ if isinstance(indexes, str):
32
+ parsed_indexes = [item.strip() for item in indexes.split(",") if item.strip()]
33
+ else:
34
+ parsed_indexes = [item.strip() for item in indexes if item.strip()]
35
+
36
+ if not parsed_indexes:
37
+ raise SearchException("No indexes were provided.")
38
+
39
+ normalized_indexes: list[str] = []
40
+ for index in parsed_indexes:
41
+ if index in {"*", "_all"} or "-" in index or "*" in index:
42
+ normalized_indexes.append(index)
43
+ else:
44
+ normalized_indexes.append(f"{DATASTORE_INDEX_PREFIX}-{index}")
45
+
46
+ return ",".join(normalized_indexes)
47
+
48
+
49
+ def get_logical_index_name(raw_index: str) -> str:
50
+ """Strip the physical datastore prefix and hot-index suffix from an index name."""
51
+ for index_prefix in sorted({DATASTORE_INDEX_PREFIX, APP_NAME}, key=len, reverse=True):
52
+ if raw_index.startswith(f"{index_prefix}-"):
53
+ raw_index = raw_index.removeprefix(f"{index_prefix}-")
54
+ break
55
+
56
+ return raw_index.removesuffix("_hot")
@@ -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.dev1283"
155
+ version = "4.0.0.dev1297"
156
156
  description = "Howler - API server"
157
157
  authors = [
158
158
  "Canadian Centre for Cyber Security <howler@cyber.gc.ca>",