Skip to content

Commit f8730dd

Browse files
committed
draft for more explicit info
on security content object mapping failure
1 parent 8cc3dbe commit f8730dd

File tree

2 files changed

+59
-38
lines changed

2 files changed

+59
-38
lines changed

contentctl/input/director.py

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,29 @@
11
import os
22
import sys
3-
from pathlib import Path
43
from dataclasses import dataclass, field
5-
from pydantic import ValidationError
4+
from pathlib import Path
65
from uuid import UUID
7-
from contentctl.input.yml_reader import YmlReader
86

9-
from contentctl.objects.detection import Detection
10-
from contentctl.objects.story import Story
7+
from pydantic import ValidationError
118

12-
from contentctl.objects.baseline import Baseline
13-
from contentctl.objects.investigation import Investigation
14-
from contentctl.objects.playbook import Playbook
15-
from contentctl.objects.deployment import Deployment
16-
from contentctl.objects.macro import Macro
17-
from contentctl.objects.lookup import LookupAdapter, Lookup
18-
from contentctl.objects.atomic import AtomicEnrichment
19-
from contentctl.objects.security_content_object import SecurityContentObject
20-
from contentctl.objects.data_source import DataSource
21-
from contentctl.objects.dashboard import Dashboard
229
from contentctl.enrichments.attack_enrichment import AttackEnrichment
2310
from contentctl.enrichments.cve_enrichment import CveEnrichment
24-
11+
from contentctl.helper.utils import Utils
12+
from contentctl.input.yml_reader import YmlReader
13+
from contentctl.objects.atomic import AtomicEnrichment
14+
from contentctl.objects.baseline import Baseline
2515
from contentctl.objects.config import validate
16+
from contentctl.objects.dashboard import Dashboard
17+
from contentctl.objects.data_source import DataSource
18+
from contentctl.objects.deployment import Deployment
19+
from contentctl.objects.detection import Detection
2620
from contentctl.objects.enums import SecurityContentType
27-
from contentctl.helper.utils import Utils
21+
from contentctl.objects.investigation import Investigation
22+
from contentctl.objects.lookup import Lookup, LookupAdapter
23+
from contentctl.objects.macro import Macro
24+
from contentctl.objects.playbook import Playbook
25+
from contentctl.objects.security_content_object import SecurityContentObject
26+
from contentctl.objects.story import Story
2827

2928

3029
@dataclass
@@ -117,15 +116,16 @@ def execute(self, input_dto: validate) -> None:
117116
MISSING_SOURCES,
118117
)
119118

120-
if len(MISSING_SOURCES) > 0:
121-
missing_sources_string = "\n 🟡 ".join(sorted(list(MISSING_SOURCES)))
119+
try:
120+
DataSource.mapNamesToSecurityContentObjects(
121+
list(MISSING_SOURCES), self.output_dto
122+
)
123+
except Exception as e:
122124
print(
123125
"WARNING: The following data_sources have been used in detections, but are not yet defined.\n"
124126
"This is not yet an error since not all data_sources have been defined, but will be convered to an error soon:\n 🟡 "
125-
f"{missing_sources_string}"
127+
f"{e}"
126128
)
127-
else:
128-
print("No missing data_sources!")
129129

130130
def createSecurityContent(self, contentType: SecurityContentType) -> None:
131131
if contentType in [

contentctl/objects/abstract_security_content_objects/security_content_object_abstract.py

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import pathlib
1313
import pprint
1414
import uuid
15+
from difflib import get_close_matches
1516
from functools import cached_property
1617
from typing import List, Optional, Tuple, Union
1718

@@ -160,16 +161,18 @@ def getReferencesListForJson(self) -> List[str]:
160161
def mapNamesToSecurityContentObjects(
161162
cls, v: list[str], director: Union[DirectorOutputDto, None]
162163
) -> list[Self]:
163-
if director is not None:
164-
name_map = director.name_to_content_map
165-
else:
166-
name_map = {}
164+
if director is None:
165+
raise Exception(
166+
"Direction was 'None' when passed to "
167+
"'mapNamesToSecurityContentObjects'. This is "
168+
"an error in the contentctl codebase which must be resolved."
169+
)
167170

168171
mappedObjects: list[Self] = []
169172
mistyped_objects: list[SecurityContentObject_Abstract] = []
170173
missing_objects: list[str] = []
171174
for object_name in v:
172-
found_object = name_map.get(object_name, None)
175+
found_object = director.name_to_content_map.get(object_name, None)
173176
if not found_object:
174177
missing_objects.append(object_name)
175178
elif not isinstance(found_object, cls):
@@ -178,22 +181,40 @@ def mapNamesToSecurityContentObjects(
178181
mappedObjects.append(found_object)
179182

180183
errors: list[str] = []
181-
if len(missing_objects) > 0:
184+
for missing_object in missing_objects:
185+
if missing_object.endswith("_filter"):
186+
# Most filter macros are defined as empty at runtime, so we do not
187+
# want to make any suggestions. It is time consuming and not helpful
188+
# to make these suggestions, so we just skip them in this check.
189+
continue
190+
matches = get_close_matches(
191+
missing_object,
192+
director.name_to_content_map.keys(),
193+
n=3,
194+
)
195+
if matches == []:
196+
matches = ["NO SUGGESTIONS"]
197+
198+
matches_string = ", ".join(matches)
182199
errors.append(
183-
f"Failed to find the following '{cls.__name__}': {missing_objects}"
200+
f"Unable to find: {missing_object}\n Suggestions: {matches_string}"
201+
)
202+
203+
for mistyped_object in mistyped_objects:
204+
matches = get_close_matches(
205+
mistyped_object.name, director.name_to_content_map.keys(), n=3
206+
)
207+
208+
errors.append(
209+
f"'{mistyped_object.name}' expected to have type '{cls.__name__}', but actually "
210+
f"had type '{type(mistyped_object).__name__}'"
184211
)
185-
if len(mistyped_objects) > 0:
186-
for mistyped_object in mistyped_objects:
187-
errors.append(
188-
f"'{mistyped_object.name}' expected to have type '{cls}', but actually "
189-
f"had type '{type(mistyped_object)}'"
190-
)
191212

192213
if len(errors) > 0:
193-
error_string = "\n - ".join(errors)
214+
error_string = "\n\n - ".join(errors)
194215
raise ValueError(
195-
f"Found {len(errors)} issues when resolving references Security Content Object "
196-
f"names:\n - {error_string}"
216+
f"Found {len(errors)} issues when resolving references to '{cls.__name__}' objects:\n"
217+
f" - {error_string}"
197218
)
198219

199220
# Sort all objects sorted by name

0 commit comments

Comments
 (0)