howler-api 4.0.0.dev676__tar.gz → 4.0.0.dev679__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 (209) hide show
  1. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/PKG-INFO +1 -1
  2. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/base.py +22 -2
  3. howler_api-4.0.0.dev679/howler/odm/mixins.py +97 -0
  4. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/case.py +2 -1
  5. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/hit.py +3 -1
  6. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/observable.py +3 -1
  7. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/pyproject.toml +1 -1
  8. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/README.md +0 -0
  9. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/__init__.py +0 -0
  10. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/actions/__init__.py +0 -0
  11. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/actions/add_label.py +0 -0
  12. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/actions/change_field.py +0 -0
  13. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/actions/demote.py +0 -0
  14. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/actions/example_plugin.py +0 -0
  15. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/actions/prioritization.py +0 -0
  16. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/actions/promote.py +0 -0
  17. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/actions/remove_label.py +0 -0
  18. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/actions/transition.py +0 -0
  19. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/__init__.py +0 -0
  20. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/base.py +0 -0
  21. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/socket.py +0 -0
  22. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/__init__.py +0 -0
  23. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/action.py +0 -0
  24. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/analytic.py +0 -0
  25. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/auth.py +0 -0
  26. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/clue.py +0 -0
  27. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/configs.py +0 -0
  28. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/dossier.py +0 -0
  29. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/help.py +0 -0
  30. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/hit.py +0 -0
  31. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/notebook.py +0 -0
  32. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/overview.py +0 -0
  33. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/search.py +0 -0
  34. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/template.py +0 -0
  35. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/tool.py +0 -0
  36. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/user.py +0 -0
  37. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/utils/__init__.py +0 -0
  38. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/utils/etag.py +0 -0
  39. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v1/view.py +0 -0
  40. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v2/__init__.py +0 -0
  41. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v2/case.py +0 -0
  42. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v2/ingest.py +0 -0
  43. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/api/v2/search.py +0 -0
  44. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/app.py +0 -0
  45. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/common/README.md +0 -0
  46. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/common/__init__.py +0 -0
  47. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/common/classification.py +0 -0
  48. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/common/classification.yml +0 -0
  49. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/common/exceptions.py +0 -0
  50. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/common/loader.py +0 -0
  51. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/common/logging/__init__.py +0 -0
  52. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/common/logging/audit.py +0 -0
  53. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/common/logging/format.py +0 -0
  54. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/common/net.py +0 -0
  55. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/common/net_static.py +0 -0
  56. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/common/random_user.py +0 -0
  57. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/common/swagger.py +0 -0
  58. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/config.py +0 -0
  59. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/cronjobs/__init__.py +0 -0
  60. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/cronjobs/retention.py +0 -0
  61. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/cronjobs/view_cleanup.py +0 -0
  62. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/README.md +0 -0
  63. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/__init__.py +0 -0
  64. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/bulk.py +0 -0
  65. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/collection.py +0 -0
  66. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/constants.py +0 -0
  67. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/exceptions.py +0 -0
  68. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/howler_store.py +0 -0
  69. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/migrations/fix_process.py +0 -0
  70. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/operations.py +0 -0
  71. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/schemas.py +0 -0
  72. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/store.py +0 -0
  73. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/support/__init__.py +0 -0
  74. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/support/build.py +0 -0
  75. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/support/schemas.py +0 -0
  76. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/datastore/types.py +0 -0
  77. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/error.py +0 -0
  78. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/external/__init__.py +0 -0
  79. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/external/generate_mitre.py +0 -0
  80. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/external/generate_sigma_rules.py +0 -0
  81. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/external/generate_tlds.py +0 -0
  82. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/external/reindex_data.py +0 -0
  83. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/external/wipe_databases.py +0 -0
  84. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/gunicorn_config.py +0 -0
  85. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/healthz.py +0 -0
  86. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/helper/__init__.py +0 -0
  87. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/helper/azure.py +0 -0
  88. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/helper/discover.py +0 -0
  89. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/helper/hit.py +0 -0
  90. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/helper/oauth.py +0 -0
  91. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/helper/search.py +0 -0
  92. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/helper/workflow.py +0 -0
  93. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/helper/ws.py +0 -0
  94. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/README.md +0 -0
  95. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/__init__.py +0 -0
  96. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/charter.txt +0 -0
  97. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/constants.py +0 -0
  98. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/helper.py +0 -0
  99. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/howler_enum.py +0 -0
  100. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/__init__.py +0 -0
  101. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/action.py +0 -0
  102. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/analytic.py +0 -0
  103. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/assemblyline.py +0 -0
  104. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/aws.py +0 -0
  105. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/azure.py +0 -0
  106. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/cbs.py +0 -0
  107. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/clue.py +0 -0
  108. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/config.py +0 -0
  109. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/dossier.py +0 -0
  110. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/__init__.py +0 -0
  111. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/agent.py +0 -0
  112. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/autonomous_system.py +0 -0
  113. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/client.py +0 -0
  114. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/cloud.py +0 -0
  115. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/code_signature.py +0 -0
  116. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/container.py +0 -0
  117. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/dns.py +0 -0
  118. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/egress.py +0 -0
  119. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/elf.py +0 -0
  120. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/email.py +0 -0
  121. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/error.py +0 -0
  122. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/event.py +0 -0
  123. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/faas.py +0 -0
  124. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/file.py +0 -0
  125. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/geo.py +0 -0
  126. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/group.py +0 -0
  127. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/hash.py +0 -0
  128. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/host.py +0 -0
  129. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/http.py +0 -0
  130. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/ingress.py +0 -0
  131. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/interface.py +0 -0
  132. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/network.py +0 -0
  133. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/observer.py +0 -0
  134. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/organization.py +0 -0
  135. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/os.py +0 -0
  136. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/pe.py +0 -0
  137. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/process.py +0 -0
  138. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/registry.py +0 -0
  139. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/related.py +0 -0
  140. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/rule.py +0 -0
  141. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/server.py +0 -0
  142. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/threat.py +0 -0
  143. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/tls.py +0 -0
  144. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/url.py +0 -0
  145. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/user.py +0 -0
  146. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/user_agent.py +0 -0
  147. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/ecs/vulnerability.py +0 -0
  148. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/gcp.py +0 -0
  149. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/howler_data.py +0 -0
  150. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/lead.py +0 -0
  151. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/localized_label.py +0 -0
  152. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/overview.py +0 -0
  153. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/pivot.py +0 -0
  154. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/record.py +0 -0
  155. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/template.py +0 -0
  156. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/user.py +0 -0
  157. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/models/view.py +0 -0
  158. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/random_data.py +0 -0
  159. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/odm/randomizer.py +0 -0
  160. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/patched.py +0 -0
  161. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/plugins/__init__.py +0 -0
  162. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/plugins/config.py +0 -0
  163. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/remote/__init__.py +0 -0
  164. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/remote/datatypes/README.md +0 -0
  165. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/remote/datatypes/__init__.py +0 -0
  166. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/remote/datatypes/counters.py +0 -0
  167. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/remote/datatypes/events.py +0 -0
  168. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/remote/datatypes/hash.py +0 -0
  169. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/remote/datatypes/lock.py +0 -0
  170. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/remote/datatypes/queues/__init__.py +0 -0
  171. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/remote/datatypes/queues/comms.py +0 -0
  172. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/remote/datatypes/queues/multi.py +0 -0
  173. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/remote/datatypes/queues/named.py +0 -0
  174. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/remote/datatypes/queues/priority.py +0 -0
  175. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/remote/datatypes/set.py +0 -0
  176. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/remote/datatypes/user_quota_tracker.py +0 -0
  177. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/security/__init__.py +0 -0
  178. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/security/socket.py +0 -0
  179. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/security/utils.py +0 -0
  180. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/__init__.py +0 -0
  181. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/action_service.py +0 -0
  182. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/analytic_service.py +0 -0
  183. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/auth_service.py +0 -0
  184. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/case_service.py +0 -0
  185. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/config_service.py +0 -0
  186. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/docs_service.py +0 -0
  187. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/dossier_service.py +0 -0
  188. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/event_service.py +0 -0
  189. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/hit_service.py +0 -0
  190. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/jwt_service.py +0 -0
  191. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/lucene_service.py +0 -0
  192. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/notebook_service.py +0 -0
  193. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/observable_service.py +0 -0
  194. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/overview_service.py +0 -0
  195. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/search_service.py +0 -0
  196. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/template_service.py +0 -0
  197. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/services/user_service.py +0 -0
  198. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/utils/__init__.py +0 -0
  199. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/utils/annotations.py +0 -0
  200. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/utils/chunk.py +0 -0
  201. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/utils/compat.py +0 -0
  202. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/utils/dict_utils.py +0 -0
  203. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/utils/isotime.py +0 -0
  204. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/utils/list_utils.py +0 -0
  205. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/utils/lucene.py +0 -0
  206. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/utils/path.py +0 -0
  207. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/utils/socket_utils.py +0 -0
  208. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/howler/utils/str_utils.py +0 -0
  209. {howler_api-4.0.0.dev676 → howler_api-4.0.0.dev679}/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.dev676
3
+ Version: 4.0.0.dev679
4
4
  Summary: Howler - API server
5
5
  License: MIT
6
6
  Keywords: howler,alerting,gc,canada,cse-cst,cse,cst,cyber,cccs
@@ -1503,11 +1503,31 @@ def recursive_set_name(field, name, to_parent=False):
1503
1503
  recursive_set_name(field.child_type, name, to_parent=True)
1504
1504
 
1505
1505
 
1506
- def model(index=None, store=None, description=None):
1507
- """Decorator to create model objects."""
1506
+ def model(index=None, store=None, description=None, id_field=None):
1507
+ """Decorator that finalizes a Model subclass for use with the datastore.
1508
+ Assigns metadata to the class (description, id field), validates that all
1509
+ declared field names are legal, recursively sets each field's name, and
1510
+ applies default index/store settings to every field.
1511
+ If ``id_field`` is not provided, it defaults to ``<classname_lower>_id``.
1512
+ Args:
1513
+ index: Default index setting applied to all fields on the model.
1514
+ store: Default store setting applied to all fields on the model.
1515
+ description: Human-readable description of the model.
1516
+ id_field: Name of the field used as the primary key. Defaults to
1517
+ ``<classname_lower>_id`` when not specified.
1518
+ Returns:
1519
+ A class decorator that configures and returns the decorated Model subclass.
1520
+ Raises:
1521
+ HowlerValueError: If any field name fails the ``FIELD_SANITIZER`` regex
1522
+ or appears in ``BANNED_FIELDS``.
1523
+ """
1508
1524
 
1509
1525
  def _finish_model(cls):
1510
1526
  cls._Model__description = description
1527
+ cls._Model__id_field = id_field
1528
+
1529
+ if cls._Model__id_field is None:
1530
+ cls._Model__id_field = f"{cls.__name__.lower()}_id"
1511
1531
 
1512
1532
  for name, field_data in cls.fields().items():
1513
1533
  if not FIELD_SANITIZER.match(name) or name in BANNED_FIELDS:
@@ -0,0 +1,97 @@
1
+ """Datastore convenience mixins for Howler ODM Model classes.
2
+
3
+ Provides :class:`DatastoreMixin`, a generic mixin that adds a class-level
4
+ ``store`` property (returning a typed :class:`ESCollection`) and instance-level
5
+ ``ds`` / ``save`` helpers so that Model subclasses can interact with the
6
+ Elasticsearch datastore without boilerplate.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from operator import attrgetter
12
+ from typing import Generic, TypeVar, overload
13
+
14
+ from howler.common.exceptions import HowlerRuntimeError
15
+ from howler.common.loader import datastore
16
+ from howler.datastore.collection import ESCollection
17
+ from howler.odm.base import Model
18
+
19
+ ModelType = TypeVar("ModelType", bound=Model)
20
+
21
+
22
+ class _ObjectsDescriptor(Generic[ModelType]):
23
+ """Descriptor that provides class-level-only access to the model's ESCollection.
24
+
25
+ Intended to be accessed exclusively via the class (e.g. ``Case.store``).
26
+ Raises ``AttributeError`` if accessed from an instance to enforce
27
+ cla # noqa: D205
28
+ """
29
+
30
+ @overload
31
+ def __get__(self, obj: None, objtype: type[ModelType]) -> ESCollection[ModelType]: ...
32
+
33
+ @overload
34
+ def __get__(self, obj: ModelType, objtype: type[ModelType]) -> ESCollection[ModelType]: ...
35
+
36
+ def __get__(self, obj: ModelType | None, objtype: type[ModelType] | None = None) -> ESCollection[ModelType]:
37
+ """Return the ESCollection for the owner class.
38
+
39
+ Args:
40
+ obj: The instance the descriptor was accessed from, or ``None``
41
+ when accessed via the class.
42
+ objtype: The owner class (e.g. ``Case``, ``Hit``).
43
+ Returns:
44
+ ESCollection[ModelType]: The datastore collection for *objtype*.
45
+ Raises:
46
+ AttributeError: If accessed from an instance (*obj* is not ``None``)
47
+ or if *objtype* cannot be determined.
48
+ """
49
+ if obj is not None:
50
+ raise HowlerRuntimeError(
51
+ f"'{type(obj).__name__}.store' is a class-level property and cannot be accessed from an instance. "
52
+ f"Use '{type(obj).__name__}.store' instead."
53
+ )
54
+
55
+ if objtype is None:
56
+ raise HowlerRuntimeError("Cannot resolve owner class for 'store' descriptor.")
57
+
58
+ index_name = objtype.__name__.lower()
59
+ return datastore()[index_name]
60
+
61
+
62
+ class DatastoreMixin(Generic[ModelType]):
63
+ """Mixin that provides convenience datastore access to Model instances.
64
+
65
+ Generic over ``ModelType`` so that the ``store`` class property returns a
66
+ correctly-typed ``ESCollection[ModelType]``. Adds a ``ds`` property for
67
+ retrieving the shared datastore connection, a ``store`` class-only property
68
+ for retrieving the model's ESCollection (raises ``AttributeError`` if accessed
69
+ from an instance), and a ``save`` method that persists the current model
70
+ instance using its class name as the index and its configured ID field as the
71
+ document key.
72
+ """
73
+
74
+ store: _ObjectsDescriptor = _ObjectsDescriptor()
75
+
76
+ @property
77
+ def ds(self):
78
+ """Return the shared datastore instance.
79
+
80
+ Returns:
81
+ The singleton datastore connection used for all persistence operations.
82
+ """
83
+ return datastore()
84
+
85
+ def save(self) -> bool:
86
+ """Persist the current model instance to the datastore.
87
+
88
+ Determines the target index from the lowercase class name, extracts the
89
+ model's ID from the configured ID field, and saves the instance.
90
+ Returns:
91
+ bool: True if the save operation succeeded, False otherwise.
92
+ """
93
+ index_name = self.__class__.__name__.lower()
94
+ id_field = self.__class__._Model__id_field # type: ignore[attr-defined]
95
+ current_id = attrgetter(id_field)(self)
96
+
97
+ return self.ds[index_name].save(current_id, self)
@@ -3,6 +3,7 @@ from typing import Any, Optional
3
3
  from howler import odm
4
4
  from howler.common.exceptions import HowlerValueError
5
5
  from howler.odm.constants import Status
6
+ from howler.odm.mixins import DatastoreMixin
6
7
  from howler.utils.compat import StrEnum
7
8
 
8
9
  CASE_ITEM_TYPES = {"observable", "hit", "case", "lead", "reference"}
@@ -92,7 +93,7 @@ class CaseEnrichment(odm.Model):
92
93
 
93
94
 
94
95
  @odm.model(index=True, store=True, description="Case model with path-based items, enrichments, rules, and tasks.")
95
- class Case(odm.Model):
96
+ class Case(DatastoreMixin["Case"], odm.Model):
96
97
  case_id: str = odm.UUID(description="A unique identifier for this case.")
97
98
  title: str = odm.Keyword(description="Case title.")
98
99
  summary: str = odm.Text(description="Short case summary.")
@@ -2,6 +2,7 @@
2
2
 
3
3
  from howler import odm
4
4
  from howler.common.logging import get_logger
5
+ from howler.odm.mixins import DatastoreMixin
5
6
  from howler.odm.models.howler_data import HowlerData
6
7
  from howler.odm.models.record import Record
7
8
 
@@ -12,8 +13,9 @@ logger = get_logger(__file__)
12
13
  index=True,
13
14
  store=True,
14
15
  description="Howler Outline schema which is an extended version of Elastic Common Schema (ECS)",
16
+ id_field="howler.id",
15
17
  )
16
- class Hit(Record):
18
+ class Hit(DatastoreMixin["Hit"], Record):
17
19
  # Howler extended fields. Deviates from ECS
18
20
  howler: HowlerData = odm.Compound(
19
21
  HowlerData,
@@ -4,6 +4,7 @@ from howler import odm
4
4
  from howler.common.exceptions import HowlerValueError
5
5
  from howler.common.logging import get_logger
6
6
  from howler.odm.howler_enum import HowlerEnum
7
+ from howler.odm.mixins import DatastoreMixin
7
8
  from howler.odm.models.record import Record
8
9
 
9
10
  logger = get_logger(__file__)
@@ -110,8 +111,9 @@ class ObservableData(odm.Model):
110
111
  index=True,
111
112
  store=True,
112
113
  description="Observable schema which is an extended version of Elastic Common Schema (ECS)",
114
+ id_field="howler.id",
113
115
  )
114
- class Observable(Record):
116
+ class Observable(DatastoreMixin["Observable"], Record):
115
117
  # Howler extended fields. Deviates from ECS
116
118
  howler: ObservableData = odm.Compound(
117
119
  ObservableData,
@@ -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.dev676"
155
+ version = "4.0.0.dev679"
156
156
  description = "Howler - API server"
157
157
  authors = [
158
158
  "Canadian Centre for Cyber Security <howler@cyber.gc.ca>",