Skip to content

Commit

Permalink
Proper support for contentctl test checking
Browse files Browse the repository at this point in the history
detections which have been affected by updated
macros and/or lookups, to include lookup CSV
and/or YML files.
  • Loading branch information
pyth0n1c committed Aug 3, 2023
1 parent 06dd1a4 commit 1c3a8a8
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 5 deletions.
26 changes: 22 additions & 4 deletions contentctl/actions/detection_testing/GitHubService.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,29 @@ def get_detections_changed(self, director: DirectorOutputDto) -> list[Detection]
else:
raise Exception(f"Unknown mode in determining differences: {difference}")

#Changes to detections, macros, and lookups should trigger a re-test for anything which uses them
changed_lookups_list = list(filter(lambda x: x.startswith("lookups"), new_content+modified_content))
changed_lookups = set()


content_to_test = list(filter(lambda x: x.startswith("detections"), new_content+modified_content ))

return []
#We must account for changes to the lookup yml AND for the underlying csv
for lookup in changed_lookups_list:
if lookup.endswith(".csv"):
lookup = lookup.replace(".csv", ".yml")
changed_lookups.add(lookup)

# At some point we should account for macros which contain other macros...
changed_macros = set(filter(lambda x: x.startswith("macros"), new_content+modified_content))
changed_macros_and_lookups = set([str(pathlib.Path(filename).absolute()) for filename in changed_lookups.union(changed_macros)])

changed_detections = set(filter(lambda x: x.startswith("detections"), new_content+modified_content))

#Check and see if content that has been modified uses any of the changed macros or lookups
for detection in director.detections:
deps = set([content.file_path for content in detection.get_content_dependencies()])
if not deps.isdisjoint(changed_macros_and_lookups):
changed_detections.add(detection.file_path)

return Detection.get_detections_from_filenames(changed_detections, director.detections)

def __init__(self, config: TestConfig):
self.repo = git.Repo(config.repo_path)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from __future__ import annotations

import uuid
import string
import requests
import time
import sys
import re
import pathlib
from pydantic import BaseModel, validator, root_validator, Extra
from dataclasses import dataclass
from typing import Union
Expand Down Expand Up @@ -64,8 +67,18 @@ class Config:


def get_content_dependencies(self)->list[SecurityContentObject]:
return self.playbooks + self.baselines +self.macros + self.lookups
return self.playbooks + self.baselines + self.macros + self.lookups

@staticmethod
def get_detections_from_filenames(detection_filenames:set[str], all_detections:list[Detection_Abstract])->list[Detection_Abstract]:
detection_filenames = set(str(pathlib.Path(filename).absolute()) for filename in detection_filenames)
detection_dict = SecurityContentObject.create_filename_to_content_dict(all_detections)

try:
return [detection_dict[detection_filename] for detection_filename in detection_filenames]
except Exception as e:
raise Exception(f"Failed to find detection object for modified detection: {str(e)}")


@validator("type")
def type_valid(cls, v, values):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
from contentctl.objects.enums import SecurityContentType
from typing import Tuple
import uuid
import pathlib

NO_FILE_BUILT_AT_RUNTIME = "NO_FILE_BUILT_AT_RUNTIME"
class SecurityContentObject_Abstract(BaseModel, abc.ABC):
contentType: SecurityContentType
name: str
Expand All @@ -17,6 +19,7 @@ class SecurityContentObject_Abstract(BaseModel, abc.ABC):
version: int = 1
id: uuid.UUID = Field(default_factory=uuid.uuid4) #we set a default here until all content has a uuid
description: str = "UNKNOWN_DESCRIPTION"
file_path: str = "NO_FILE_BUILT_AT_RUNTIME"

@validator('name')
def name_max_length(cls, v):
Expand Down Expand Up @@ -58,4 +61,13 @@ def get_objects_by_name(names_to_find:set[str], objects_to_search:list[SecurityC
found_names = set([obj.name for obj in found_objects])
missing_names = names_to_find - found_names
return found_objects,missing_names

@staticmethod
def create_filename_to_content_dict(all_objects:list[SecurityContentObject_Abstract])->dict[str,SecurityContentObject_Abstract]:
name_dict:dict[str,SecurityContentObject_Abstract] = dict()

for object in all_objects:
name_dict[str(pathlib.Path(object.file_path))] = object

return name_dict

0 comments on commit 1c3a8a8

Please sign in to comment.