howler-api 2.13.0.dev332__py3-none-any.whl → 2.13.0.dev342__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of howler-api might be problematic. Click here for more details.

howler/api/v1/search.py CHANGED
@@ -1,6 +1,9 @@
1
+ import re
2
+ from copy import deepcopy
1
3
  from typing import Any, Union
2
4
 
3
5
  from elasticsearch import BadRequestError
6
+ from elasticsearch._sync.client.indices import IndicesClient
4
7
  from flask import request
5
8
  from sigma.backends.elasticsearch import LuceneBackend
6
9
  from sigma.rule import SigmaRule
@@ -14,7 +17,7 @@ from howler.common.swagger import generate_swagger_docs
14
17
  from howler.datastore.exceptions import SearchException
15
18
  from howler.helper.search import get_collection, get_default_sort, has_access_control, list_all_fields
16
19
  from howler.security import api_login
17
- from howler.services import hit_service
20
+ from howler.services import hit_service, lucene_service
18
21
 
19
22
  SUB_API = "search"
20
23
  search_api = make_subapi_blueprint(SUB_API, api_version=1)
@@ -146,6 +149,76 @@ def search(index, **kwargs):
146
149
  return bad_request(err=f"SearchException: {e}")
147
150
 
148
151
 
152
+ @generate_swagger_docs()
153
+ @search_api.route("/<index>/explain", methods=["GET", "POST"])
154
+ @api_login(required_priv=["R"])
155
+ def explain_query(index, **kwargs):
156
+ """Search through specified index for a given Lucene query. Uses Lucene search syntax for query.
157
+
158
+ Variables:
159
+ index => Index to explain against (hit, user,...)
160
+
161
+ Arguments:
162
+ query => Lucene Query to explain
163
+
164
+ Data Block:
165
+ # Note that the data block is for POST requests only!
166
+ {
167
+ "query": "id:*", # Lucene Query to explain
168
+ }
169
+
170
+
171
+ Result Example:
172
+ {
173
+ 'valid': True,
174
+ 'explanations': [
175
+ {
176
+ 'valid': True,
177
+ 'explanation': 'ConstantScore(FieldExistsQuery [field=id])'
178
+ }
179
+ ]
180
+ }
181
+ """
182
+ user = kwargs["user"]
183
+ collection = get_collection(index, user)
184
+
185
+ if collection is None:
186
+ return bad_request(err=f"Not a valid index to explain: {index}")
187
+
188
+ fields = ["query"]
189
+ multi_fields: list[str] = []
190
+
191
+ params, req_data = generate_params(request, fields, multi_fields)
192
+
193
+ params["as_obj"] = False
194
+
195
+ query = req_data.get("query", None)
196
+ if not query:
197
+ return bad_request(err="There was no query.")
198
+
199
+ # This regex checks for lucene phrases (i.e. the "Example Analytic" part of howler.analytic:"Example Analytic")
200
+ # And then escapes them.
201
+ # https://regex101.com/r/8u5F6a/1
202
+ escaped_lucene = re.sub(r'((:\()?(".+?")(\)?))', lucene_service.replace_lucene_phrase, query)
203
+
204
+ try:
205
+ indices_client = IndicesClient(datastore().hit.datastore.client)
206
+
207
+ result = deepcopy(
208
+ indices_client.validate_query(q=escaped_lucene, explain=True, index=collection().index_name).body
209
+ )
210
+
211
+ del result["_shards"]
212
+
213
+ for explanation in result["explanations"]:
214
+ del explanation["index"]
215
+
216
+ return ok(result)
217
+ except Exception as e:
218
+ logger.exception("Exception on query explanation")
219
+ return bad_request(err=f"Exception: {e}")
220
+
221
+
149
222
  @generate_swagger_docs()
150
223
  @search_api.route("/<index>/eql", methods=["GET", "POST"])
151
224
  @api_login(required_priv=["R"])
howler/odm/models/lead.py CHANGED
@@ -2,18 +2,9 @@
2
2
  from typing import Optional
3
3
 
4
4
  from howler import odm
5
- from howler.odm.howler_enum import HowlerEnum
6
5
  from howler.odm.models.localized_label import LocalizedLabel
7
6
 
8
7
 
9
- class Formats(str, HowlerEnum):
10
- BOREALIS = "borealis"
11
- MARKDOWN = "markdown"
12
-
13
- def __str__(self) -> str:
14
- return self.value
15
-
16
-
17
8
  @odm.model(
18
9
  index=False,
19
10
  store=True,
@@ -24,7 +15,7 @@ class Lead(odm.Model):
24
15
  description="An optional icon to use in the tab display for this dossier.", optional=True
25
16
  )
26
17
  label: LocalizedLabel = odm.Compound(LocalizedLabel, description="Labels for the lead in the UI.")
27
- format: str = odm.Enum(values=Formats, description="The format of the lead. ")
18
+ format: str = odm.Keyword(description="The format of the lead.")
28
19
  content: str = odm.Text(
29
20
  description="The data for the content. Could be a link, raw markdown text, or other valid lead format.",
30
21
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: howler-api
3
- Version: 2.13.0.dev332
3
+ Version: 2.13.0.dev342
4
4
  Summary: Howler - API server
5
5
  License: MIT
6
6
  Keywords: howler,alerting,gc,canada,cse-cst,cse,cst,cyber,cccs
@@ -24,7 +24,7 @@ howler/api/v1/help.py,sha256=hqBvzW-DYX-I4Q85dbCQgpHsXyWDXp06a1fE9zhFMH4,823
24
24
  howler/api/v1/hit.py,sha256=HKaI72k7VC0v4QPjE2zcAV6jizvY2ZWEpk1BiAklvgU,34031
25
25
  howler/api/v1/notebook.py,sha256=-cahdJ9u1lAB_nheztayHKtXvoPZcj04N8nqQ2U-HLo,2015
26
26
  howler/api/v1/overview.py,sha256=e-WiHuMvOPy8Y7xIGnceagdI0_jebqlgDxi6GE6tfaA,4999
27
- howler/api/v1/search.py,sha256=o6jQCPnlmEhTF3lgtsDo4J_g0JQorJxxliNKZWG4wXo,24257
27
+ howler/api/v1/search.py,sha256=24r1vaYaxDhddzDR-c5dBdRKyag6aIggvHSWPWudqN8,26372
28
28
  howler/api/v1/template.py,sha256=oexzUpAMVdgI6IOXITPx0iEfZIVP-kvlExRdFd6QVdk,5769
29
29
  howler/api/v1/tool.py,sha256=6CN5LIXgxaAvxEHE6s4IFtAEhQo_zBLtl6ghbM8whjE,6737
30
30
  howler/api/v1/user.py,sha256=YQh6eCAi4bsC_w9eGX0ZgnLoFL4z4efEc1knJsZhj4k,13842
@@ -140,7 +140,7 @@ howler/odm/models/ecs/vulnerability.py,sha256=iX2TUmCZTJjwyMcOmxiHg-pfoEwX8Wx-h8
140
140
  howler/odm/models/gcp.py,sha256=FLwaQVcfFeE5AbIhEB_Ge2UL-HjPdldY04Nrm9Mq7kk,675
141
141
  howler/odm/models/hit.py,sha256=kgzk3RzgKGvHdtNG0iMRxCtLPD73-BFFU9A_IxJcOHI,13396
142
142
  howler/odm/models/howler_data.py,sha256=3bzKQ_vSP_rK20S_U4PkXzsmBL1uqSaIOHZmoPuRkS8,12473
143
- howler/odm/models/lead.py,sha256=QDzX0IdSWRZgBBNtHAyXMaOJa7bP41CDYQWN_vadkV4,1107
143
+ howler/odm/models/lead.py,sha256=lqapGWZ4u22Asib48o7wAzramnFY9EkRybmb4olsyrA,904
144
144
  howler/odm/models/localized_label.py,sha256=G7gfQ1cngiI4KprqldHWE1KHkAgK4AG_JsfHxVRdsRs,361
145
145
  howler/odm/models/overview.py,sha256=kvZcMYPDlkJEGa0L1jq9pG0RFjLOVudC64-2GTWVu2w,684
146
146
  howler/odm/models/pivot.py,sha256=VLZl5DHnLfmCM2ZU5sAye0qu18toCaFcYLYraXct2GM,1398
@@ -194,7 +194,7 @@ howler/utils/path.py,sha256=DfOU4i4zSs4wchHoE8iE7aWVLkTxiC_JRGepF2hBYBk,690
194
194
  howler/utils/socket_utils.py,sha256=nz1SklC9xBHUSfHyTJjpq3mbozX1GDf01WzdGxfaUII,2212
195
195
  howler/utils/str_utils.py,sha256=HE8Hqh2HlOLaj16w0H9zKOyDJLp-f1LQ50y_WeGZaEk,8389
196
196
  howler/utils/uid.py,sha256=p9dsqyvZ-lpiAuzZWCPCeEM99kdk0Ly9czf04HNdSuw,1341
197
- howler_api-2.13.0.dev332.dist-info/METADATA,sha256=hvBwPOBT37W4CKYSMyisUAtKQ5HQajbISIfm7_8-sRU,2805
198
- howler_api-2.13.0.dev332.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
199
- howler_api-2.13.0.dev332.dist-info/entry_points.txt,sha256=Lu9SBGvwe0wczJHmc-RudC24lmQk7tv3ZBXon9RIihg,259
200
- howler_api-2.13.0.dev332.dist-info/RECORD,,
197
+ howler_api-2.13.0.dev342.dist-info/METADATA,sha256=k-G9s9TnSg4YhLHLrWrci6m16oU21RbtaJ1kwD_F-3M,2805
198
+ howler_api-2.13.0.dev342.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
199
+ howler_api-2.13.0.dev342.dist-info/entry_points.txt,sha256=Lu9SBGvwe0wczJHmc-RudC24lmQk7tv3ZBXon9RIihg,259
200
+ howler_api-2.13.0.dev342.dist-info/RECORD,,