contentctl 4.4.7__py3-none-any.whl → 5.0.0a2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- contentctl/actions/build.py +39 -27
- contentctl/actions/detection_testing/DetectionTestingManager.py +0 -1
- contentctl/actions/detection_testing/GitService.py +132 -72
- contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructure.py +32 -26
- contentctl/actions/detection_testing/progress_bar.py +6 -6
- contentctl/actions/detection_testing/views/DetectionTestingView.py +4 -4
- contentctl/actions/new_content.py +98 -81
- contentctl/actions/test.py +4 -5
- contentctl/actions/validate.py +2 -1
- contentctl/contentctl.py +114 -80
- contentctl/helper/utils.py +0 -14
- contentctl/input/director.py +5 -5
- contentctl/input/new_content_questions.py +2 -2
- contentctl/input/yml_reader.py +11 -6
- contentctl/objects/abstract_security_content_objects/detection_abstract.py +228 -120
- contentctl/objects/abstract_security_content_objects/security_content_object_abstract.py +5 -7
- contentctl/objects/alert_action.py +2 -1
- contentctl/objects/atomic.py +1 -0
- contentctl/objects/base_test.py +4 -3
- contentctl/objects/base_test_result.py +3 -3
- contentctl/objects/baseline.py +26 -6
- contentctl/objects/baseline_tags.py +2 -3
- contentctl/objects/config.py +789 -596
- contentctl/objects/constants.py +4 -1
- contentctl/objects/correlation_search.py +89 -95
- contentctl/objects/data_source.py +5 -6
- contentctl/objects/deployment.py +2 -10
- contentctl/objects/deployment_email.py +2 -1
- contentctl/objects/deployment_notable.py +2 -1
- contentctl/objects/deployment_phantom.py +2 -1
- contentctl/objects/deployment_rba.py +2 -1
- contentctl/objects/deployment_scheduling.py +2 -1
- contentctl/objects/deployment_slack.py +2 -1
- contentctl/objects/detection_tags.py +7 -42
- contentctl/objects/drilldown.py +1 -0
- contentctl/objects/enums.py +21 -58
- contentctl/objects/investigation.py +6 -5
- contentctl/objects/investigation_tags.py +2 -3
- contentctl/objects/lookup.py +145 -63
- contentctl/objects/macro.py +2 -3
- contentctl/objects/mitre_attack_enrichment.py +2 -2
- contentctl/objects/observable.py +3 -1
- contentctl/objects/playbook_tags.py +5 -1
- contentctl/objects/rba.py +90 -0
- contentctl/objects/risk_event.py +87 -144
- contentctl/objects/story_tags.py +1 -2
- contentctl/objects/test_attack_data.py +2 -1
- contentctl/objects/unit_test_baseline.py +2 -1
- contentctl/output/api_json_output.py +233 -220
- contentctl/output/conf_output.py +51 -44
- contentctl/output/conf_writer.py +201 -125
- contentctl/output/data_source_writer.py +0 -1
- contentctl/output/json_writer.py +2 -4
- contentctl/output/svg_output.py +1 -1
- contentctl/output/templates/analyticstories_detections.j2 +1 -1
- contentctl/output/templates/collections.j2 +1 -1
- contentctl/output/templates/doc_detections.j2 +0 -5
- contentctl/output/templates/savedsearches_detections.j2 +8 -3
- contentctl/output/templates/transforms.j2 +4 -4
- contentctl/output/yml_writer.py +15 -0
- contentctl/templates/detections/endpoint/anomalous_usage_of_7zip.yml +16 -34
- {contentctl-4.4.7.dist-info → contentctl-5.0.0a2.dist-info}/METADATA +5 -4
- {contentctl-4.4.7.dist-info → contentctl-5.0.0a2.dist-info}/RECORD +66 -69
- {contentctl-4.4.7.dist-info → contentctl-5.0.0a2.dist-info}/WHEEL +1 -1
- contentctl/objects/event_source.py +0 -11
- contentctl/output/detection_writer.py +0 -28
- contentctl/output/new_content_yml_output.py +0 -56
- contentctl/output/yml_output.py +0 -66
- {contentctl-4.4.7.dist-info → contentctl-5.0.0a2.dist-info}/LICENSE.md +0 -0
- {contentctl-4.4.7.dist-info → contentctl-5.0.0a2.dist-info}/entry_points.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from typing import Union, Any
|
|
2
|
-
from enum import
|
|
2
|
+
from enum import StrEnum
|
|
3
3
|
|
|
4
4
|
from pydantic import ConfigDict, BaseModel
|
|
5
5
|
from splunklib.data import Record # type: ignore
|
|
@@ -10,7 +10,7 @@ from contentctl.helper.utils import Utils
|
|
|
10
10
|
# TODO (#267): Align test reporting more closely w/ status enums (as it relates to "untested")
|
|
11
11
|
# TODO (PEX-432): add status "UNSET" so that we can make sure the result is always of this enum
|
|
12
12
|
# type; remove mypy ignores associated w/ these typing issues once we do
|
|
13
|
-
class TestResultStatus(
|
|
13
|
+
class TestResultStatus(StrEnum):
|
|
14
14
|
"""Enum for test status (e.g. pass/fail)"""
|
|
15
15
|
# Test failed (detection did NOT fire appropriately)
|
|
16
16
|
FAIL = "fail"
|
|
@@ -113,7 +113,7 @@ class BaseTestResult(BaseModel):
|
|
|
113
113
|
# Exceptions and enums cannot be serialized, so convert to str
|
|
114
114
|
if isinstance(getattr(self, field), Exception):
|
|
115
115
|
summary_dict[field] = str(getattr(self, field))
|
|
116
|
-
elif isinstance(getattr(self, field),
|
|
116
|
+
elif isinstance(getattr(self, field), StrEnum):
|
|
117
117
|
summary_dict[field] = str(getattr(self, field))
|
|
118
118
|
else:
|
|
119
119
|
summary_dict[field] = getattr(self, field)
|
contentctl/objects/baseline.py
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
|
|
2
2
|
from __future__ import annotations
|
|
3
|
-
from typing import Annotated,
|
|
4
|
-
|
|
3
|
+
from typing import Annotated, List,Any, TYPE_CHECKING
|
|
4
|
+
if TYPE_CHECKING:
|
|
5
|
+
from contentctl.input.director import DirectorOutputDto
|
|
6
|
+
|
|
7
|
+
from pydantic import field_validator, ValidationInfo, Field, model_serializer, computed_field
|
|
5
8
|
from contentctl.objects.deployment import Deployment
|
|
6
9
|
from contentctl.objects.security_content_object import SecurityContentObject
|
|
7
10
|
from contentctl.objects.enums import DataModel
|
|
@@ -9,21 +12,34 @@ from contentctl.objects.baseline_tags import BaselineTags
|
|
|
9
12
|
|
|
10
13
|
from contentctl.objects.config import CustomApp
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
from contentctl.objects.lookup import Lookup
|
|
13
16
|
from contentctl.objects.constants import CONTENTCTL_MAX_SEARCH_NAME_LENGTH,CONTENTCTL_BASELINE_STANZA_NAME_FORMAT_TEMPLATE
|
|
14
17
|
|
|
15
18
|
class Baseline(SecurityContentObject):
|
|
16
19
|
name:str = Field(...,max_length=CONTENTCTL_MAX_SEARCH_NAME_LENGTH)
|
|
17
20
|
type: Annotated[str,Field(pattern="^Baseline$")] = Field(...)
|
|
18
|
-
datamodel: Optional[List[DataModel]] = None
|
|
19
21
|
search: str = Field(..., min_length=4)
|
|
20
22
|
how_to_implement: str = Field(..., min_length=4)
|
|
21
23
|
known_false_positives: str = Field(..., min_length=4)
|
|
22
24
|
tags: BaselineTags = Field(...)
|
|
23
|
-
|
|
25
|
+
lookups: list[Lookup] = Field([], validate_default=True)
|
|
24
26
|
# enrichment
|
|
25
27
|
deployment: Deployment = Field({})
|
|
26
|
-
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@field_validator('lookups', mode="before")
|
|
31
|
+
@classmethod
|
|
32
|
+
def getBaselineLookups(cls, v:list[str], info:ValidationInfo) -> list[Lookup]:
|
|
33
|
+
'''
|
|
34
|
+
This function has been copied and renamed from the Detection_Abstract class
|
|
35
|
+
'''
|
|
36
|
+
director:DirectorOutputDto = info.context.get("output_dto",None)
|
|
37
|
+
search: str | None = info.data.get("search",None)
|
|
38
|
+
if search is None:
|
|
39
|
+
raise ValueError("Search was None - is this file missing the search field?")
|
|
40
|
+
|
|
41
|
+
lookups = Lookup.get_lookups(search, director)
|
|
42
|
+
return lookups
|
|
27
43
|
|
|
28
44
|
def get_conf_stanza_name(self, app:CustomApp)->str:
|
|
29
45
|
stanza_name = CONTENTCTL_BASELINE_STANZA_NAME_FORMAT_TEMPLATE.format(app_label=app.label, detection_name=self.name)
|
|
@@ -34,6 +50,10 @@ class Baseline(SecurityContentObject):
|
|
|
34
50
|
def getDeployment(cls, v:Any, info:ValidationInfo)->Deployment:
|
|
35
51
|
return Deployment.getDeployment(v,info)
|
|
36
52
|
|
|
53
|
+
@computed_field
|
|
54
|
+
@property
|
|
55
|
+
def datamodel(self) -> List[DataModel]:
|
|
56
|
+
return [dm for dm in DataModel if dm in self.search]
|
|
37
57
|
|
|
38
58
|
@model_serializer
|
|
39
59
|
def serialize_model(self):
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from pydantic import BaseModel, Field, field_validator, ValidationInfo, model_serializer
|
|
2
|
+
from pydantic import BaseModel, Field, field_validator, ValidationInfo, model_serializer, ConfigDict
|
|
3
3
|
from typing import List, Any, Union
|
|
4
4
|
|
|
5
5
|
from contentctl.objects.story import Story
|
|
@@ -12,12 +12,12 @@ from contentctl.objects.enums import SecurityDomain
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class BaselineTags(BaseModel):
|
|
15
|
+
model_config = ConfigDict(extra="forbid")
|
|
15
16
|
analytic_story: list[Story] = Field(...)
|
|
16
17
|
#deployment: Deployment = Field('SET_IN_GET_DEPLOYMENT_FUNCTION')
|
|
17
18
|
# TODO (#223): can we remove str from the possible types here?
|
|
18
19
|
detections: List[Union[Detection,str]] = Field(...)
|
|
19
20
|
product: List[SecurityContentProductName] = Field(...,min_length=1)
|
|
20
|
-
required_fields: List[str] = Field(...,min_length=1)
|
|
21
21
|
security_domain: SecurityDomain = Field(...)
|
|
22
22
|
|
|
23
23
|
|
|
@@ -33,7 +33,6 @@ class BaselineTags(BaseModel):
|
|
|
33
33
|
"analytic_story": [story.name for story in self.analytic_story],
|
|
34
34
|
"detections": [detection.name for detection in self.detections if isinstance(detection,Detection)],
|
|
35
35
|
"product": self.product,
|
|
36
|
-
"required_fields":self.required_fields,
|
|
37
36
|
"security_domain":self.security_domain,
|
|
38
37
|
"deployments": None
|
|
39
38
|
}
|