contentctl 5.0.0a2__py3-none-any.whl → 5.0.1__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/__init__.py +1 -1
- contentctl/actions/build.py +88 -55
- contentctl/actions/deploy_acs.py +29 -24
- contentctl/actions/detection_testing/DetectionTestingManager.py +66 -41
- contentctl/actions/detection_testing/GitService.py +2 -4
- contentctl/actions/detection_testing/generate_detection_coverage_badge.py +48 -30
- contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructure.py +163 -124
- contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructureContainer.py +45 -32
- contentctl/actions/detection_testing/progress_bar.py +3 -0
- contentctl/actions/detection_testing/views/DetectionTestingView.py +15 -18
- contentctl/actions/detection_testing/views/DetectionTestingViewCLI.py +1 -5
- contentctl/actions/detection_testing/views/DetectionTestingViewFile.py +2 -2
- contentctl/actions/detection_testing/views/DetectionTestingViewWeb.py +1 -4
- contentctl/actions/doc_gen.py +9 -5
- contentctl/actions/initialize.py +45 -33
- contentctl/actions/inspect.py +118 -61
- contentctl/actions/new_content.py +83 -53
- contentctl/actions/release_notes.py +276 -146
- contentctl/actions/reporting.py +23 -19
- contentctl/actions/test.py +31 -25
- contentctl/actions/validate.py +54 -34
- contentctl/api.py +54 -45
- contentctl/contentctl.py +10 -10
- contentctl/enrichments/attack_enrichment.py +112 -72
- contentctl/enrichments/cve_enrichment.py +34 -28
- contentctl/enrichments/splunk_app_enrichment.py +38 -36
- contentctl/helper/link_validator.py +101 -78
- contentctl/helper/splunk_app.py +69 -41
- contentctl/helper/utils.py +58 -39
- contentctl/input/director.py +69 -37
- contentctl/input/new_content_questions.py +26 -34
- contentctl/input/yml_reader.py +22 -17
- contentctl/objects/abstract_security_content_objects/detection_abstract.py +255 -323
- contentctl/objects/abstract_security_content_objects/security_content_object_abstract.py +111 -46
- contentctl/objects/alert_action.py +8 -8
- contentctl/objects/annotated_types.py +1 -1
- contentctl/objects/atomic.py +64 -54
- contentctl/objects/base_test.py +2 -1
- contentctl/objects/base_test_result.py +16 -8
- contentctl/objects/baseline.py +47 -35
- contentctl/objects/baseline_tags.py +29 -22
- contentctl/objects/config.py +1 -1
- contentctl/objects/constants.py +32 -58
- contentctl/objects/correlation_search.py +75 -55
- contentctl/objects/dashboard.py +55 -41
- contentctl/objects/data_source.py +13 -13
- contentctl/objects/deployment.py +44 -37
- contentctl/objects/deployment_email.py +1 -1
- contentctl/objects/deployment_notable.py +2 -1
- contentctl/objects/deployment_phantom.py +5 -5
- contentctl/objects/deployment_rba.py +1 -1
- contentctl/objects/deployment_scheduling.py +1 -1
- contentctl/objects/deployment_slack.py +1 -1
- contentctl/objects/detection.py +5 -2
- contentctl/objects/detection_metadata.py +1 -0
- contentctl/objects/detection_stanza.py +7 -2
- contentctl/objects/detection_tags.py +54 -64
- contentctl/objects/drilldown.py +66 -35
- contentctl/objects/enums.py +61 -43
- contentctl/objects/errors.py +16 -24
- contentctl/objects/integration_test.py +3 -3
- contentctl/objects/integration_test_result.py +1 -0
- contentctl/objects/investigation.py +53 -31
- contentctl/objects/investigation_tags.py +29 -17
- contentctl/objects/lookup.py +234 -113
- contentctl/objects/macro.py +55 -38
- contentctl/objects/manual_test.py +3 -3
- contentctl/objects/manual_test_result.py +1 -0
- contentctl/objects/mitre_attack_enrichment.py +17 -16
- contentctl/objects/notable_action.py +2 -1
- contentctl/objects/notable_event.py +1 -3
- contentctl/objects/playbook.py +37 -35
- contentctl/objects/playbook_tags.py +22 -16
- contentctl/objects/rba.py +68 -11
- contentctl/objects/risk_analysis_action.py +15 -11
- contentctl/objects/risk_event.py +27 -20
- contentctl/objects/risk_object.py +1 -0
- contentctl/objects/savedsearches_conf.py +9 -7
- contentctl/objects/security_content_object.py +5 -2
- contentctl/objects/story.py +54 -49
- contentctl/objects/story_tags.py +56 -44
- contentctl/objects/test_group.py +5 -2
- contentctl/objects/threat_object.py +1 -0
- contentctl/objects/throttling.py +27 -18
- contentctl/objects/unit_test.py +3 -4
- contentctl/objects/unit_test_baseline.py +4 -5
- contentctl/objects/unit_test_result.py +6 -6
- contentctl/output/api_json_output.py +22 -22
- contentctl/output/attack_nav_output.py +21 -21
- contentctl/output/attack_nav_writer.py +29 -37
- contentctl/output/conf_output.py +230 -174
- contentctl/output/data_source_writer.py +38 -25
- contentctl/output/doc_md_output.py +53 -27
- contentctl/output/jinja_writer.py +19 -15
- contentctl/output/json_writer.py +20 -8
- contentctl/output/svg_output.py +56 -38
- contentctl/output/templates/analyticstories_detections.j2 +1 -1
- contentctl/output/templates/analyticstories_stories.j2 +1 -1
- contentctl/output/templates/es_investigations_investigations.j2 +1 -1
- contentctl/output/templates/es_investigations_stories.j2 +1 -1
- contentctl/output/templates/savedsearches_baselines.j2 +2 -2
- contentctl/output/templates/savedsearches_detections.j2 +2 -8
- contentctl/output/templates/savedsearches_investigations.j2 +2 -2
- contentctl/output/templates/transforms.j2 +2 -4
- contentctl/output/yml_writer.py +18 -24
- contentctl/templates/stories/cobalt_strike.yml +1 -0
- {contentctl-5.0.0a2.dist-info → contentctl-5.0.1.dist-info}/METADATA +1 -1
- contentctl-5.0.1.dist-info/RECORD +168 -0
- contentctl/actions/initialize_old.py +0 -245
- contentctl/objects/observable.py +0 -39
- contentctl-5.0.0a2.dist-info/RECORD +0 -170
- {contentctl-5.0.0a2.dist-info → contentctl-5.0.1.dist-info}/LICENSE.md +0 -0
- {contentctl-5.0.0a2.dist-info → contentctl-5.0.1.dist-info}/WHEEL +0 -0
- {contentctl-5.0.0a2.dist-info → contentctl-5.0.1.dist-info}/entry_points.txt +0 -0
contentctl/objects/baseline.py
CHANGED
|
@@ -1,23 +1,33 @@
|
|
|
1
|
-
|
|
2
1
|
from __future__ import annotations
|
|
3
|
-
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Annotated, Any, List, Literal
|
|
4
|
+
|
|
4
5
|
if TYPE_CHECKING:
|
|
5
6
|
from contentctl.input.director import DirectorOutputDto
|
|
6
7
|
|
|
7
|
-
from pydantic import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
from pydantic import (
|
|
9
|
+
Field,
|
|
10
|
+
ValidationInfo,
|
|
11
|
+
computed_field,
|
|
12
|
+
field_validator,
|
|
13
|
+
model_serializer,
|
|
14
|
+
)
|
|
12
15
|
|
|
16
|
+
from contentctl.objects.baseline_tags import BaselineTags
|
|
13
17
|
from contentctl.objects.config import CustomApp
|
|
14
|
-
|
|
18
|
+
from contentctl.objects.constants import (
|
|
19
|
+
CONTENTCTL_BASELINE_STANZA_NAME_FORMAT_TEMPLATE,
|
|
20
|
+
CONTENTCTL_MAX_SEARCH_NAME_LENGTH,
|
|
21
|
+
)
|
|
22
|
+
from contentctl.objects.deployment import Deployment
|
|
23
|
+
from contentctl.objects.enums import DataModel, DetectionStatus
|
|
15
24
|
from contentctl.objects.lookup import Lookup
|
|
16
|
-
from contentctl.objects.
|
|
25
|
+
from contentctl.objects.security_content_object import SecurityContentObject
|
|
26
|
+
|
|
17
27
|
|
|
18
28
|
class Baseline(SecurityContentObject):
|
|
19
|
-
name:str = Field(...,max_length=CONTENTCTL_MAX_SEARCH_NAME_LENGTH)
|
|
20
|
-
type: Annotated[str,Field(pattern="^Baseline$")] = Field(...)
|
|
29
|
+
name: str = Field(..., max_length=CONTENTCTL_MAX_SEARCH_NAME_LENGTH)
|
|
30
|
+
type: Annotated[str, Field(pattern="^Baseline$")] = Field(...)
|
|
21
31
|
search: str = Field(..., min_length=4)
|
|
22
32
|
how_to_implement: str = Field(..., min_length=4)
|
|
23
33
|
known_false_positives: str = Field(..., min_length=4)
|
|
@@ -25,31 +35,33 @@ class Baseline(SecurityContentObject):
|
|
|
25
35
|
lookups: list[Lookup] = Field([], validate_default=True)
|
|
26
36
|
# enrichment
|
|
27
37
|
deployment: Deployment = Field({})
|
|
38
|
+
status: Literal[DetectionStatus.production, DetectionStatus.deprecated]
|
|
28
39
|
|
|
29
|
-
|
|
30
|
-
@field_validator('lookups', mode="before")
|
|
40
|
+
@field_validator("lookups", mode="before")
|
|
31
41
|
@classmethod
|
|
32
|
-
def getBaselineLookups(cls, v:list[str], info:ValidationInfo) -> list[Lookup]:
|
|
33
|
-
|
|
42
|
+
def getBaselineLookups(cls, v: list[str], info: ValidationInfo) -> list[Lookup]:
|
|
43
|
+
"""
|
|
34
44
|
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)
|
|
45
|
+
"""
|
|
46
|
+
director: DirectorOutputDto = info.context.get("output_dto", None)
|
|
47
|
+
search: str | None = info.data.get("search", None)
|
|
38
48
|
if search is None:
|
|
39
49
|
raise ValueError("Search was None - is this file missing the search field?")
|
|
40
|
-
|
|
50
|
+
|
|
41
51
|
lookups = Lookup.get_lookups(search, director)
|
|
42
52
|
return lookups
|
|
43
53
|
|
|
44
|
-
def get_conf_stanza_name(self, app:CustomApp)->str:
|
|
45
|
-
stanza_name = CONTENTCTL_BASELINE_STANZA_NAME_FORMAT_TEMPLATE.format(
|
|
54
|
+
def get_conf_stanza_name(self, app: CustomApp) -> str:
|
|
55
|
+
stanza_name = CONTENTCTL_BASELINE_STANZA_NAME_FORMAT_TEMPLATE.format(
|
|
56
|
+
app_label=app.label, detection_name=self.name
|
|
57
|
+
)
|
|
46
58
|
self.check_conf_stanza_max_length(stanza_name)
|
|
47
59
|
return stanza_name
|
|
48
60
|
|
|
49
61
|
@field_validator("deployment", mode="before")
|
|
50
|
-
def getDeployment(cls, v:Any, info:ValidationInfo)->Deployment:
|
|
51
|
-
return Deployment.getDeployment(v,info)
|
|
52
|
-
|
|
62
|
+
def getDeployment(cls, v: Any, info: ValidationInfo) -> Deployment:
|
|
63
|
+
return Deployment.getDeployment(v, info)
|
|
64
|
+
|
|
53
65
|
@computed_field
|
|
54
66
|
@property
|
|
55
67
|
def datamodel(self) -> List[DataModel]:
|
|
@@ -57,21 +69,21 @@ class Baseline(SecurityContentObject):
|
|
|
57
69
|
|
|
58
70
|
@model_serializer
|
|
59
71
|
def serialize_model(self):
|
|
60
|
-
#Call serializer for parent
|
|
72
|
+
# Call serializer for parent
|
|
61
73
|
super_fields = super().serialize_model()
|
|
62
|
-
|
|
63
|
-
#All fields custom to this model
|
|
64
|
-
model= {
|
|
74
|
+
|
|
75
|
+
# All fields custom to this model
|
|
76
|
+
model = {
|
|
65
77
|
"tags": self.tags.model_dump(),
|
|
66
78
|
"type": self.type,
|
|
67
79
|
"search": self.search,
|
|
68
|
-
"how_to_implement":self.how_to_implement,
|
|
69
|
-
"known_false_positives":self.known_false_positives,
|
|
80
|
+
"how_to_implement": self.how_to_implement,
|
|
81
|
+
"known_false_positives": self.known_false_positives,
|
|
70
82
|
"datamodel": self.datamodel,
|
|
71
83
|
}
|
|
72
|
-
|
|
73
|
-
#Combine fields from this model with fields from parent
|
|
84
|
+
|
|
85
|
+
# Combine fields from this model with fields from parent
|
|
74
86
|
super_fields.update(model)
|
|
75
|
-
|
|
76
|
-
#return the model
|
|
77
|
-
return super_fields
|
|
87
|
+
|
|
88
|
+
# return the model
|
|
89
|
+
return super_fields
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from pydantic import
|
|
2
|
+
from pydantic import (
|
|
3
|
+
BaseModel,
|
|
4
|
+
Field,
|
|
5
|
+
field_validator,
|
|
6
|
+
ValidationInfo,
|
|
7
|
+
model_serializer,
|
|
8
|
+
ConfigDict,
|
|
9
|
+
)
|
|
3
10
|
from typing import List, Any, Union
|
|
4
11
|
|
|
5
12
|
from contentctl.objects.story import Story
|
|
@@ -8,35 +15,35 @@ from contentctl.objects.enums import SecurityContentProductName
|
|
|
8
15
|
from contentctl.objects.enums import SecurityDomain
|
|
9
16
|
|
|
10
17
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
18
|
class BaselineTags(BaseModel):
|
|
15
19
|
model_config = ConfigDict(extra="forbid")
|
|
16
20
|
analytic_story: list[Story] = Field(...)
|
|
17
|
-
#deployment: Deployment = Field('SET_IN_GET_DEPLOYMENT_FUNCTION')
|
|
21
|
+
# deployment: Deployment = Field('SET_IN_GET_DEPLOYMENT_FUNCTION')
|
|
18
22
|
# TODO (#223): can we remove str from the possible types here?
|
|
19
|
-
detections: List[Union[Detection,str]] = Field(...)
|
|
20
|
-
product: List[SecurityContentProductName] = Field(...,min_length=1)
|
|
23
|
+
detections: List[Union[Detection, str]] = Field(...)
|
|
24
|
+
product: List[SecurityContentProductName] = Field(..., min_length=1)
|
|
21
25
|
security_domain: SecurityDomain = Field(...)
|
|
22
26
|
|
|
27
|
+
@field_validator("analytic_story", mode="before")
|
|
28
|
+
def getStories(cls, v: Any, info: ValidationInfo) -> List[Story]:
|
|
29
|
+
return Story.mapNamesToSecurityContentObjects(
|
|
30
|
+
v, info.context.get("output_dto", None)
|
|
31
|
+
)
|
|
23
32
|
|
|
24
|
-
@field_validator("analytic_story",mode="before")
|
|
25
|
-
def getStories(cls, v:Any, info:ValidationInfo)->List[Story]:
|
|
26
|
-
return Story.mapNamesToSecurityContentObjects(v, info.context.get("output_dto",None))
|
|
27
|
-
|
|
28
|
-
|
|
29
33
|
@model_serializer
|
|
30
|
-
def serialize_model(self):
|
|
31
|
-
#All fields custom to this model
|
|
32
|
-
model= {
|
|
34
|
+
def serialize_model(self):
|
|
35
|
+
# All fields custom to this model
|
|
36
|
+
model = {
|
|
33
37
|
"analytic_story": [story.name for story in self.analytic_story],
|
|
34
|
-
"detections": [
|
|
38
|
+
"detections": [
|
|
39
|
+
detection.name
|
|
40
|
+
for detection in self.detections
|
|
41
|
+
if isinstance(detection, Detection)
|
|
42
|
+
],
|
|
35
43
|
"product": self.product,
|
|
36
|
-
"security_domain":self.security_domain,
|
|
37
|
-
"deployments": None
|
|
44
|
+
"security_domain": self.security_domain,
|
|
45
|
+
"deployments": None,
|
|
38
46
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return model
|
|
47
|
+
|
|
48
|
+
# return the model
|
|
49
|
+
return model
|
contentctl/objects/config.py
CHANGED
|
@@ -1162,7 +1162,7 @@ class release_notes(Config_Base):
|
|
|
1162
1162
|
p = self.path / "dist"
|
|
1163
1163
|
try:
|
|
1164
1164
|
p.mkdir(exist_ok=True, parents=True)
|
|
1165
|
-
except Exception:
|
|
1165
|
+
except Exception as e:
|
|
1166
1166
|
raise Exception(
|
|
1167
1167
|
f"Error making the directory '{p}' to hold release_notes: {str(e)}"
|
|
1168
1168
|
)
|
contentctl/objects/constants.py
CHANGED
|
@@ -15,7 +15,7 @@ ATTACK_TACTICS_KILLCHAIN_MAPPING = {
|
|
|
15
15
|
"Collection": "Exploitation",
|
|
16
16
|
"Command And Control": "Command and Control",
|
|
17
17
|
"Exfiltration": "Actions on Objectives",
|
|
18
|
-
"Impact": "Actions on Objectives"
|
|
18
|
+
"Impact": "Actions on Objectives",
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
SES_CONTEXT_MAPPING = {
|
|
@@ -65,7 +65,7 @@ SES_CONTEXT_MAPPING = {
|
|
|
65
65
|
"Other:Policy Violation": 82,
|
|
66
66
|
"Other:Threat Intelligence": 83,
|
|
67
67
|
"Other:Flight Risk": 84,
|
|
68
|
-
"Other:Removable Storage": 85
|
|
68
|
+
"Other:Removable Storage": 85,
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
SES_KILL_CHAIN_MAPPINGS = {
|
|
@@ -76,49 +76,9 @@ SES_KILL_CHAIN_MAPPINGS = {
|
|
|
76
76
|
"Exploitation": 4,
|
|
77
77
|
"Installation": 5,
|
|
78
78
|
"Command and Control": 6,
|
|
79
|
-
"Actions on Objectives": 7
|
|
79
|
+
"Actions on Objectives": 7,
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
# TODO (cmcginley): @ljstella should this be removed? also referenced in new_content.py
|
|
83
|
-
SES_OBSERVABLE_ROLE_MAPPING = {
|
|
84
|
-
"Other": -1,
|
|
85
|
-
"Unknown": 0,
|
|
86
|
-
"Actor": 1,
|
|
87
|
-
"Target": 2,
|
|
88
|
-
"Attacker": 3,
|
|
89
|
-
"Victim": 4,
|
|
90
|
-
"Parent Process": 5,
|
|
91
|
-
"Child Process": 6,
|
|
92
|
-
"Known Bad": 7,
|
|
93
|
-
"Data Loss": 8,
|
|
94
|
-
"Observer": 9
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
# TODO (cmcginley): @ljstella should this be removed? also referenced in new_content.py
|
|
98
|
-
SES_OBSERVABLE_TYPE_MAPPING = {
|
|
99
|
-
"Unknown": 0,
|
|
100
|
-
"Hostname": 1,
|
|
101
|
-
"IP Address": 2,
|
|
102
|
-
"MAC Address": 3,
|
|
103
|
-
"User Name": 4,
|
|
104
|
-
"Email Address": 5,
|
|
105
|
-
"URL String": 6,
|
|
106
|
-
"File Name": 7,
|
|
107
|
-
"File Hash": 8,
|
|
108
|
-
"Process Name": 9,
|
|
109
|
-
"Resource UID": 10,
|
|
110
|
-
"Endpoint": 20,
|
|
111
|
-
"User": 21,
|
|
112
|
-
"Email": 22,
|
|
113
|
-
"Uniform Resource Locator": 23,
|
|
114
|
-
"File": 24,
|
|
115
|
-
"Process": 25,
|
|
116
|
-
"Geo Location": 26,
|
|
117
|
-
"Container": 27,
|
|
118
|
-
"Registry Key": 28,
|
|
119
|
-
"Registry Value": 29,
|
|
120
|
-
"Other": 99
|
|
121
|
-
}
|
|
122
82
|
|
|
123
83
|
SES_ATTACK_TACTICS_ID_MAPPING = {
|
|
124
84
|
"Reconnaissance": "TA0043",
|
|
@@ -134,24 +94,19 @@ SES_ATTACK_TACTICS_ID_MAPPING = {
|
|
|
134
94
|
"Collection": "TA0009",
|
|
135
95
|
"Command_and_Control": "TA0011",
|
|
136
96
|
"Exfiltration": "TA0010",
|
|
137
|
-
"Impact": "TA0040"
|
|
97
|
+
"Impact": "TA0040",
|
|
138
98
|
}
|
|
139
99
|
|
|
140
|
-
# TODO (cmcginley): is this just for the transition testing?
|
|
141
|
-
RBA_OBSERVABLE_ROLE_MAPPING = {
|
|
142
|
-
"Attacker": 0,
|
|
143
|
-
"Victim": 1
|
|
144
|
-
}
|
|
145
100
|
|
|
146
101
|
# The relative path to the directory where any apps/packages will be downloaded
|
|
147
102
|
DOWNLOADS_DIRECTORY = "downloads"
|
|
148
103
|
|
|
149
104
|
# Maximum length of the name field for a search.
|
|
150
|
-
# This number is derived from a limitation that exists in
|
|
105
|
+
# This number is derived from a limitation that exists in
|
|
151
106
|
# ESCU where a search cannot be edited, due to validation
|
|
152
107
|
# errors, if its name is longer than 99 characters.
|
|
153
108
|
# When an saved search is cloned in Enterprise Security User Interface,
|
|
154
|
-
# it is wrapped in the following:
|
|
109
|
+
# it is wrapped in the following:
|
|
155
110
|
# {Detection.tags.security_domain} - {SEARCH_STANZA_NAME} - Rule
|
|
156
111
|
# Similarly, when we generate the search stanza name in contentctl, it
|
|
157
112
|
# is app.label - detection.name - Rule
|
|
@@ -160,16 +115,35 @@ DOWNLOADS_DIRECTORY = "downloads"
|
|
|
160
115
|
# or in ESCU:
|
|
161
116
|
# ESCU - {detection.name} - Rule,
|
|
162
117
|
# this gives us a maximum length below.
|
|
163
|
-
# When an ESCU search is cloned, it will
|
|
118
|
+
# When an ESCU search is cloned, it will
|
|
164
119
|
# have a full name like (the following is NOT a typo):
|
|
165
120
|
# Endpoint - ESCU - Name of Search From YML File - Rule - Rule
|
|
166
121
|
# The math below accounts for all these caveats
|
|
167
122
|
ES_MAX_STANZA_LENGTH = 99
|
|
168
|
-
CONTENTCTL_DETECTION_STANZA_NAME_FORMAT_TEMPLATE =
|
|
123
|
+
CONTENTCTL_DETECTION_STANZA_NAME_FORMAT_TEMPLATE = (
|
|
124
|
+
"{app_label} - {detection_name} - Rule"
|
|
125
|
+
)
|
|
169
126
|
CONTENTCTL_BASELINE_STANZA_NAME_FORMAT_TEMPLATE = "{app_label} - {detection_name}"
|
|
170
|
-
CONTENTCTL_RESPONSE_TASK_NAME_FORMAT_TEMPLATE =
|
|
127
|
+
CONTENTCTL_RESPONSE_TASK_NAME_FORMAT_TEMPLATE = (
|
|
128
|
+
"{app_label} - {detection_name} - Response Task"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
ES_SEARCH_STANZA_NAME_FORMAT_AFTER_CLONING_IN_PRODUCT_TEMPLATE = (
|
|
132
|
+
"{security_domain_value} - {search_name} - Rule"
|
|
133
|
+
)
|
|
134
|
+
SECURITY_DOMAIN_MAX_LENGTH = max(
|
|
135
|
+
[len(SecurityDomain[value]) for value in SecurityDomain._member_map_]
|
|
136
|
+
)
|
|
137
|
+
CONTENTCTL_MAX_STANZA_LENGTH = ES_MAX_STANZA_LENGTH - len(
|
|
138
|
+
ES_SEARCH_STANZA_NAME_FORMAT_AFTER_CLONING_IN_PRODUCT_TEMPLATE.format(
|
|
139
|
+
security_domain_value="X" * SECURITY_DOMAIN_MAX_LENGTH, search_name=""
|
|
140
|
+
)
|
|
141
|
+
)
|
|
142
|
+
CONTENTCTL_MAX_SEARCH_NAME_LENGTH = CONTENTCTL_MAX_STANZA_LENGTH - len(
|
|
143
|
+
CONTENTCTL_DETECTION_STANZA_NAME_FORMAT_TEMPLATE.format(
|
|
144
|
+
app_label="ESCU", detection_name=""
|
|
145
|
+
)
|
|
146
|
+
)
|
|
171
147
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
CONTENTCTL_MAX_STANZA_LENGTH = ES_MAX_STANZA_LENGTH - len(ES_SEARCH_STANZA_NAME_FORMAT_AFTER_CLONING_IN_PRODUCT_TEMPLATE.format(security_domain_value="X"*SECURITY_DOMAIN_MAX_LENGTH,search_name=""))
|
|
175
|
-
CONTENTCTL_MAX_SEARCH_NAME_LENGTH = CONTENTCTL_MAX_STANZA_LENGTH - len(CONTENTCTL_DETECTION_STANZA_NAME_FORMAT_TEMPLATE.format(app_label="ESCU", detection_name=""))
|
|
148
|
+
DEPRECATED_TEMPLATE = "**WARNING**, this {content_type} has been marked **DEPRECATED** by the Splunk Threat Research Team. This means that it will no longer be maintained or supported. If you have any questions feel free to email us at: research@splunk.com. {description}"
|
|
149
|
+
EXPERIMENTAL_TEMPLATE = "**WARNING**, this {content_type} is marked **EXPERIMENTAL** by the Splunk Threat Research Team. This means that the {content_type} has been manually tested but we do not have the associated attack data to perform automated testing or cannot share this attack dataset due to its sensitive nature. If you have any questions feel free to email us at: research@splunk.com. {description}"
|