1
+ from __future__ import annotations
1
2
from pydantic import BaseModel , Field
3
+ from typing import TYPE_CHECKING
4
+ if TYPE_CHECKING :
5
+ from contentctl .objects .detection import Detection
6
+ from contentctl .objects .enums import AnalyticsType
7
+ SEARCH_PLACEHOLDER = "%original_detection_search%"
8
+
2
9
class Drilldown (BaseModel ):
3
- name : str = Field (...,min_length = 5 )
10
+ name : str = Field (..., description = "The name of the drilldown search" , min_length = 5 )
4
11
search : str = Field (..., description = "The text of a drilldown search. This must be valid SPL." , min_length = 1 )
5
- earliest_offset :str = "$info_min_time$"
6
- latest_offset :str = "$info_max_time$"
12
+ earliest_offset :str = Field (default = "$info_min_time$" , description = "Earliest offset time for the drilldown search" , min_length = 1 )
13
+ latest_offset :str = Field (default = "$info_max_time$" , description = "Latest offset time for the driolldown search" , min_length = 1 )
14
+
15
+ @classmethod
16
+ def constructDrilldownFromDetection (cls , detection : Detection ) -> Drilldown :
17
+ if len ([f"${ o .name } $" for o in detection .tags .observable if o .role [0 ] == "Victim" ]) == 0 and detection .type != AnalyticsType .Hunting :
18
+ print ("no victim!" )
19
+ # print(detection.tags.observable)
20
+ # print(detection.file_path)
21
+ name_field = "View the detection results for " + ' and ' + '' .join ([f"${ o .name } $" for o in detection .tags .observable if o .type [0 ] == "Victim" ])
22
+ search_field = f"{ detection .search } | search " + ' ' .join ([f"o.name = ${ o .name } $" for o in detection .tags .observable ])
23
+ return cls (name = name_field , search = search_field )
24
+
25
+
26
+ def perform_search_substitutions (self , detection :Detection )-> None :
27
+ if (self .search .count ("%" ) % 2 ) or (self .search .count ("$" ) % 2 ):
28
+ print ("\n \n Warning - a non-even number of '%' or '$' characters were found in the\n "
29
+ f"drilldown search '{ self .search } ' for Detection { detection .file_path } .\n "
30
+ "If this was intentional, then please ignore this warning.\n " )
31
+ self .search = self .search .replace (SEARCH_PLACEHOLDER , detection .search )
32
+
33
+
34
+
0 commit comments