Skip to content

Commit c849694

Browse files
adjusting for some of the changes in build and ES 8.0
1 parent 84a0d1b commit c849694

File tree

1 file changed

+85
-51
lines changed

1 file changed

+85
-51
lines changed

contentctl/objects/content_versioning_service.py

Lines changed: 85 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@
1616
from contentctl.objects.correlation_search import ResultIterator
1717
from contentctl.helper.utils import Utils
1818

19+
# TODO (cmcginley):
20+
# - [x] version naming scheme seems to have changed from X - X to X.X
21+
# - [x] sourcetype no longer holds detection name but instead is stash_common_detection_model
22+
# - [ ] action.escu.full_search_name no longer available
23+
# - [ ] check to see if we can get "name"
24+
# - [ ] move strings to enums
25+
# - [ ] additionally, timeout for cms_parser seems to need more time
26+
1927
# TODO (cmcginley): suppress logging
2028
# Suppress logging by default; enable for local testing
2129
ENABLE_LOGGING = True
@@ -55,6 +63,15 @@ class ContentVersioningService(BaseModel):
5563
)
5664
)
5765

66+
def model_post_init(self, __context: Any) -> None:
67+
super().model_post_init(__context)
68+
69+
# Log instance details
70+
self.logger.info(
71+
f"[{self.infrastructure.instance_name} ({self.infrastructure.instance_address})] "
72+
"Initing ContentVersioningService"
73+
)
74+
5875
# The cached job on the splunk instance of the cms events
5976
_cms_main_job: splunklib.Job | None = PrivateAttr(default=None)
6077

@@ -167,6 +184,10 @@ def activate_versioning(self) -> None:
167184
if not self.is_versioning_activated:
168185
raise Exception("Something went wrong, content versioning is still disabled.")
169186

187+
self.logger.info(
188+
f"[{self.infrastructure.instance_name}] Versioning service successfully activated"
189+
)
190+
170191
@computed_field
171192
@cached_property
172193
def cms_fields(self) -> list[str]:
@@ -178,7 +199,6 @@ def cms_fields(self) -> list[str]:
178199
"""
179200
return [
180201
"app_name",
181-
f"action.{self.global_config.app.label.lower()}.full_search_name",
182202
"detection_id",
183203
"version",
184204
"action.correlationsearch.label",
@@ -214,6 +234,10 @@ def force_cms_parser(self) -> None:
214234
if not self.is_cms_parser_enabled:
215235
raise Exception("Something went wrong, cms_parser is still disabled.")
216236

237+
self.logger.info(
238+
f"[{self.infrastructure.instance_name}] cms_parser successfully toggled to force run"
239+
)
240+
217241
def wait_for_cms_main(self) -> None:
218242
"""
219243
Checks the cms_main index until it has the expected number of events, or it times out.
@@ -225,27 +249,36 @@ def wait_for_cms_main(self) -> None:
225249
elapsed_sleep_time = 0
226250
num_tries = 0
227251
time_to_sleep = 2**num_tries
228-
max_sleep = 300
252+
max_sleep = 480
229253

230254
# Loop until timeout
231255
while elapsed_sleep_time < max_sleep:
232256
# Sleep, and add the time to the elapsed counter
233-
self.logger.info(f"Waiting {time_to_sleep} for cms_parser to finish")
257+
self.logger.info(
258+
f"[{self.infrastructure.instance_name}] Waiting {time_to_sleep} for cms_parser to "
259+
"finish"
260+
)
234261
time.sleep(time_to_sleep)
235262
elapsed_sleep_time += time_to_sleep
236263
self.logger.info(
237-
f"Checking cms_main (attempt #{num_tries + 1} - {elapsed_sleep_time} seconds elapsed of "
238-
f"{max_sleep} max)"
264+
f"[{self.infrastructure.instance_name}] Checking cms_main (attempt #{num_tries + 1}"
265+
f" - {elapsed_sleep_time} seconds elapsed of {max_sleep} max)"
239266
)
240267

241268
# Check if the number of CMS events matches or exceeds the number of detections
242269
if self.get_num_cms_events() >= len(self.detections):
243270
self.logger.info(
244-
f"Found {self.get_num_cms_events(use_cache=True)} events in cms_main which "
271+
f"[{self.infrastructure.instance_name}] Found "
272+
f"{self.get_num_cms_events(use_cache=True)} events in cms_main which "
245273
f"meets or exceeds the expected {len(self.detections)}."
246274
)
247275
break
248-
276+
else:
277+
self.logger.info(
278+
f"[{self.infrastructure.instance_name}] Found "
279+
f"{self.get_num_cms_events(use_cache=True)} matching events in cms_main; "
280+
f"expecting {len(self.detections)}. Continuing to wait..."
281+
)
249282
# Update the number of times we've tried, and increment the time to sleep
250283
num_tries += 1
251284
time_to_sleep = 2**num_tries
@@ -278,7 +311,7 @@ def _query_cms_main(self, use_cache: bool = False) -> splunklib.Job:
278311
f"search index=cms_main app_name=\"{self.global_config.app.appid}\" | "
279312
f"fields {', '.join(self.cms_fields)}"
280313
)
281-
self.logger.debug(f"Query on cms_main: {query}")
314+
self.logger.debug(f"[{self.infrastructure.instance_name}] Query on cms_main: {query}")
282315

283316
# Get the job as a blocking operation, set the cache, and return
284317
self._cms_main_job = self.service.search(query, exec_mode="blocking") # type: ignore
@@ -317,14 +350,14 @@ def validate_content_against_cms(self) -> None:
317350
# Generate an error for the count mismatch
318351
if result_count != len(self.detections):
319352
msg = (
320-
f"Expected {len(self.detections)} matching events in cms_main, but "
321-
f"found {result_count}."
353+
f"[{self.infrastructure.instance_name}] Expected {len(self.detections)} matching "
354+
f"events in cms_main, but found {result_count}."
322355
)
323356
self.logger.error(msg)
324357
exceptions.append(Exception(msg))
325358
self.logger.info(
326-
f"Expecting {len(self.detections)} matching events in cms_main, "
327-
f"found {result_count}."
359+
f"[{self.infrastructure.instance_name}] Expecting {len(self.detections)} matching "
360+
f"events in cms_main, found {result_count}."
328361
)
329362

330363
# Init some counters and a mapping of detections to their names
@@ -351,30 +384,34 @@ def validate_content_against_cms(self) -> None:
351384
# Get the name of the search in the CMS event and attempt to use pattern matching
352385
# to strip the prefix and suffix used for the savedsearches.conf name so we can
353386
# compare to the detection
354-
cms_entry_name = cms_event["sourcetype"]
355-
self.logger.info(f"{offset}: Matching cms_main entry '{cms_entry_name}' against detections")
356-
ptrn = re.compile(r"^" + self.global_config.app.label + r" - (?P<cms_entry_name>.+) - Rule$")
357-
match = ptrn.match(cms_event["sourcetype"])
387+
cms_entry_name = cms_event["action.correlationsearch.label"]
388+
self.logger.info(
389+
f"[{self.infrastructure.instance_name}] {offset}: Matching cms_main entry "
390+
f"'{cms_entry_name}' against detections"
391+
)
392+
ptrn = re.compile(r"^" + self.global_config.app.label + r" - (?P<stripped_cms_entry_name>.+) - Rule$")
393+
match = ptrn.match(cms_event["action.correlationsearch.label"])
358394

359395
# Report any errors extracting the detection name from the longer rule name
360396
if match is None:
361397
msg = (
362-
f"[{cms_entry_name}]: Entry in cms_main did not match the expected naming "
363-
"scheme; cannot compare to our detections."
398+
f"[{self.infrastructure.instance_name}] [{cms_entry_name}]: Entry in "
399+
"cms_main did not match the expected naming scheme; cannot compare to our "
400+
"detections."
364401
)
365402
self.logger.error(msg)
366403
exceptions.append(Exception(msg))
367404
continue
368405

369406
# Extract the detection name if matching was successful
370-
cms_entry_name = match.group("cms_entry_name")
407+
stripped_cms_entry_name = match.group("stripped_cms_entry_name")
371408

372409
# If CMS entry name matches one of the detections already matched, we've got an
373410
# unexpected repeated entry
374-
if cms_entry_name in matched_detections:
411+
if stripped_cms_entry_name in matched_detections:
375412
msg = (
376-
f"[{cms_entry_name}]: Detection appears more than once in the cms_main "
377-
"index."
413+
f"[{self.infrastructure.instance_name}] [{stripped_cms_entry_name}]: Detection "
414+
f"appears more than once in the cms_main index."
378415
)
379416
self.logger.error(msg)
380417
exceptions.append(Exception(msg))
@@ -385,10 +422,10 @@ def validate_content_against_cms(self) -> None:
385422
for detection_name in remaining_detections:
386423
# If we find a match, break this loop, set the found flag and move the detection
387424
# from those that still need to matched to those already matched
388-
if cms_entry_name == detection_name:
425+
if stripped_cms_entry_name == detection_name:
389426
self.logger.info(
390-
f"{offset}: Succesfully matched cms_main entry against detection "
391-
f"('{detection_name}')!"
427+
f"[{self.infrastructure.instance_name}] {offset}: Succesfully matched "
428+
f"cms_main entry against detection ('{detection_name}')!"
392429
)
393430

394431
# Validate other fields of the cms_event against the detection
@@ -410,8 +447,8 @@ def validate_content_against_cms(self) -> None:
410447
# Generate an exception if we couldn't match the CMS main entry to a detection
411448
if result_matches_detection is False:
412449
msg = (
413-
f"[{cms_entry_name}]: Could not match entry in cms_main against any "
414-
"of the expected detections."
450+
f"[{self.infrastructure.instance_name}] [{stripped_cms_entry_name}]: Could not "
451+
"match entry in cms_main against any of the expected detections."
415452
)
416453
self.logger.error(msg)
417454
exceptions.append(Exception(msg))
@@ -422,8 +459,8 @@ def validate_content_against_cms(self) -> None:
422459
# Generate exceptions for the unmatched detections
423460
for detection_name in remaining_detections:
424461
msg = (
425-
f"[{detection_name}]: Detection not found in cms_main; there may be an "
426-
"issue with savedsearches.conf"
462+
f"[{self.infrastructure.instance_name}] [{detection_name}]: Detection not "
463+
"found in cms_main; there may be an issue with savedsearches.conf"
427464
)
428465
self.logger.error(msg)
429466
exceptions.append(Exception(msg))
@@ -436,7 +473,10 @@ def validate_content_against_cms(self) -> None:
436473
)
437474

438475
# Else, we've matched/validated all detections against cms_main
439-
self.logger.info("Matched and validated all detections against cms_main!")
476+
self.logger.info(
477+
f"[{self.infrastructure.instance_name}] Matched and validated all detections against "
478+
"cms_main!"
479+
)
440480

441481
def validate_detection_against_cms_event(
442482
self,
@@ -458,47 +498,41 @@ def validate_detection_against_cms_event(
458498
# TODO (cmcginley): validate additional fields between the cms_event and the detection
459499

460500
cms_uuid = uuid.UUID(cms_event["detection_id"])
461-
full_search_key = f"action.{self.global_config.app.label.lower()}.full_search_name"
462501
rule_name_from_detection = f"{self.global_config.app.label} - {detection.name} - Rule"
463502

464503
# Compare the UUIDs
465504
if cms_uuid != detection.id:
466505
msg = (
467-
f"[{detection.name}]: UUID in cms_event ('{cms_uuid}') does not match UUID in "
468-
f"detection ('{detection.id}')"
506+
f"[{self.infrastructure.instance_name}] [{detection.name}]: UUID in cms_event "
507+
f"('{cms_uuid}') does not match UUID in detection ('{detection.id}')"
469508
)
470509
self.logger.error(msg)
471510
return Exception(msg)
472-
elif cms_event["version"] != f"{detection.version}-1":
473-
# Compare the versions (we append '-1' to the detection version to be in line w/ the
511+
elif cms_event["version"] != f"{detection.version}.1":
512+
# Compare the versions (we append '.1' to the detection version to be in line w/ the
474513
# internal representation in ES)
475514
msg = (
476-
f"[{detection.name}]: Version in cms_event ('{cms_event['version']}') does not "
477-
f"match version in detection ('{detection.version}-1')"
478-
)
479-
self.logger.error(msg)
480-
return Exception(msg)
481-
elif cms_event[full_search_key] != rule_name_from_detection:
482-
# Compare the full search name
483-
msg = (
484-
f"[{detection.name}]: Full search name in cms_event "
485-
f"('{cms_event[full_search_key]}') does not match detection name"
515+
f"[{self.infrastructure.instance_name}] [{detection.name}]: Version in cms_event "
516+
f"('{cms_event['version']}') does not match version in detection "
517+
f"('{detection.version}.1')"
486518
)
487519
self.logger.error(msg)
488520
return Exception(msg)
489-
elif cms_event["action.correlationsearch.label"] != f"{self.global_config.app.label} - {detection.name} - Rule":
521+
elif cms_event["action.correlationsearch.label"] != rule_name_from_detection:
490522
# Compare the correlation search label
491523
msg = (
492-
f"[{detection.name}]: Correlation search label in cms_event "
493-
f"('{cms_event['action.correlationsearch.label']}') does not match detection name"
524+
f"[{self.infrastructure.instance_name}][{detection.name}]: Correlation search "
525+
f"label in cms_event ('{cms_event['action.correlationsearch.label']}') does not "
526+
"match detection name"
494527
)
495528
self.logger.error(msg)
496529
return Exception(msg)
497-
elif cms_event["sourcetype"] != f"{self.global_config.app.label} - {detection.name} - Rule":
530+
elif cms_event["sourcetype"] != "stash_common_detection_model":
498531
# Compare the full search name
499532
msg = (
500-
f"[{detection.name}]: Sourcetype in cms_event ('{cms_event[f'sourcetype']}') does "
501-
f"not match detection name"
533+
f"[{self.infrastructure.instance_name}] [{detection.name}]: Unexpected sourcetype "
534+
f"in cms_event ('{cms_event[f'sourcetype']}'); expected "
535+
"'stash_common_detection_model'"
502536
)
503537
self.logger.error(msg)
504538
return Exception(msg)

0 commit comments

Comments
 (0)