Skip to content

Commit e787bfd

Browse files
committed
Another rewrite
1 parent 97e2a61 commit e787bfd

File tree

1 file changed

+46
-28
lines changed

1 file changed

+46
-28
lines changed

contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructure.py

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,17 +1062,18 @@ def retry_search_until_timeout(
10621062
# Consolidate a set of the distinct observable field names
10631063
observable_fields_set = set([o.name for o in detection.tags.observable]) # keeping this around for later
10641064
risk_object_fields_set = set([o.name for o in detection.tags.observable if "Victim" in o.role ]) # just the "Risk Objects"
1065-
threat_object_fields_set = set([o.name for o in detection.tags.observable if "Attacker" in o.role]) # saving this for later
1065+
threat_object_fields_set = set([o.name for o in detection.tags.observable if "Attacker" in o.role]) # just the "threat objects"
10661066

10671067
# Ensure the search had at least one result
10681068
if int(job.content.get("resultCount", "0")) > 0:
10691069
# Initialize the test result
10701070
test.result = UnitTestResult()
10711071

10721072
# Initialize the collection of fields that are empty that shouldn't be
1073+
present_threat_objects: set[str] = set()
10731074
empty_fields: set[str] = set()
1074-
full_result_null_set: set[str] = set()
1075-
full_null_threat_set: set[str] = set()
1075+
1076+
10761077

10771078
result_count: int = 0
10781079
# Filter out any messages in the results
@@ -1083,9 +1084,8 @@ def retry_search_until_timeout(
10831084
# If not a message, it is a dict and we will process it
10841085
results_fields_set = set(result.keys())
10851086
# Guard against first events (relevant later)
1086-
result_count += 1
10871087

1088-
# Identify any observable fields that are not available in the results
1088+
# Identify any risk object fields that are not available in the results
10891089
missing_risk_objects = risk_object_fields_set - results_fields_set
10901090
if len(missing_risk_objects) > 0:
10911091
# Report a failure in such cases
@@ -1098,25 +1098,35 @@ def retry_search_until_timeout(
10981098
duration=time.time() - search_start_time,
10991099
)
11001100

1101-
return
1101+
return
11021102

11031103
# If we find one or more risk object fields that contain the string "null" then they were
11041104
# not populated and we should throw an error. This can happen if there is a typo
11051105
# on a field. In this case, the field will appear but will not contain any values
11061106
current_empty_fields: set[str] = set()
1107-
for field in risk_object_fields_set:
1107+
1108+
for field in observable_fields_set:
11081109
if result.get(field, 'null') == 'null':
1109-
current_empty_fields.add(field)
1110-
if result_count == 1:
1111-
full_result_null_set.add(field)
1110+
if field in risk_object_fields_set:
1111+
e = Exception(f"The risk object field {field} is missing in at least one result.")
1112+
test.result.set_job_content(
1113+
job.content,
1114+
self.infrastructure,
1115+
TestResultStatus.FAIL,
1116+
exception=e,
1117+
duration=time.time() - search_start_time,
1118+
)
1119+
return
11121120
else:
1113-
if field in full_result_null_set:
1114-
continue
1121+
if field in threat_object_fields_set:
1122+
current_empty_fields.add(field)
11151123
else:
1116-
if field in full_result_null_set:
1117-
full_result_null_set.remove(field)
1118-
1124+
if field in threat_object_fields_set:
1125+
present_threat_objects.add(field)
1126+
continue
1127+
11191128

1129+
11201130
# If everything succeeded up until now, and no empty fields are found in the
11211131
# current result, then the search was a success
11221132
if len(current_empty_fields) == 0:
@@ -1132,22 +1142,30 @@ def retry_search_until_timeout(
11321142
empty_fields = empty_fields.union(current_empty_fields)
11331143

11341144

1145+
missing_threat_objects = threat_object_fields_set - present_threat_objects
1146+
# Report a failure if there were empty fields in a threat object in all results
1147+
if len(missing_threat_objects) > 0:
1148+
e = Exception(
1149+
f"One or more required threat object fields {missing_threat_objects} contained 'null' values in all events. "
1150+
"Is the data being parsed correctly or is there an error in the naming of a field?"
1151+
)
1152+
test.result.set_job_content(
1153+
job.content,
1154+
self.infrastructure,
1155+
TestResultStatus.FAIL,
1156+
exception=e,
1157+
duration=time.time() - search_start_time,
1158+
)
1159+
return
11351160

1136-
# Report a failure if there were empty fields in some results
11371161

1138-
e = Exception(
1139-
f"One or more required observable fields {empty_fields} contained 'null' values. Is the "
1140-
"data being parsed correctly or is there an error in the naming of a field?"
1141-
)
11421162
test.result.set_job_content(
1143-
job.content,
1144-
self.infrastructure,
1145-
TestResultStatus.ERROR,
1146-
exception=e,
1147-
duration=time.time() - search_start_time,
1148-
)
1149-
1150-
return
1163+
job.content,
1164+
self.infrastructure,
1165+
TestResultStatus.PASS,
1166+
duration=time.time() - search_start_time,
1167+
)
1168+
return
11511169

11521170
else:
11531171
# Report a failure if there were no results at all

0 commit comments

Comments
 (0)