contentctl 5.0.0a0__py3-none-any.whl → 5.0.0a3__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 +134 -76
- 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 +78 -50
- 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 +12 -13
- 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 +250 -314
- contentctl/objects/abstract_security_content_objects/security_content_object_abstract.py +58 -36
- 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 +41 -30
- contentctl/objects/baseline_tags.py +29 -22
- contentctl/objects/config.py +772 -560
- contentctl/objects/constants.py +29 -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 +41 -26
- 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 +14 -8
- 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 +45 -44
- 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/savedsearches_detections.j2 +1 -1
- contentctl/output/templates/transforms.j2 +2 -2
- contentctl/output/yml_writer.py +18 -24
- {contentctl-5.0.0a0.dist-info → contentctl-5.0.0a3.dist-info}/METADATA +1 -1
- contentctl-5.0.0a3.dist-info/RECORD +168 -0
- contentctl/actions/initialize_old.py +0 -245
- contentctl/objects/observable.py +0 -39
- contentctl-5.0.0a0.dist-info/RECORD +0 -170
- {contentctl-5.0.0a0.dist-info → contentctl-5.0.0a3.dist-info}/LICENSE.md +0 -0
- {contentctl-5.0.0a0.dist-info → contentctl-5.0.0a3.dist-info}/WHEEL +0 -0
- {contentctl-5.0.0a0.dist-info → contentctl-5.0.0a3.dist-info}/entry_points.txt +0 -0
contentctl/objects/baseline.py
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
|
|
2
1
|
from __future__ import annotations
|
|
3
|
-
from typing import Annotated, List,Any, TYPE_CHECKING
|
|
2
|
+
from typing import Annotated, List, Any, TYPE_CHECKING
|
|
3
|
+
|
|
4
4
|
if TYPE_CHECKING:
|
|
5
5
|
from contentctl.input.director import DirectorOutputDto
|
|
6
6
|
|
|
7
|
-
from pydantic import
|
|
7
|
+
from pydantic import (
|
|
8
|
+
field_validator,
|
|
9
|
+
ValidationInfo,
|
|
10
|
+
Field,
|
|
11
|
+
model_serializer,
|
|
12
|
+
computed_field,
|
|
13
|
+
)
|
|
8
14
|
from contentctl.objects.deployment import Deployment
|
|
9
15
|
from contentctl.objects.security_content_object import SecurityContentObject
|
|
10
16
|
from contentctl.objects.enums import DataModel
|
|
@@ -13,11 +19,15 @@ from contentctl.objects.baseline_tags import BaselineTags
|
|
|
13
19
|
from contentctl.objects.config import CustomApp
|
|
14
20
|
|
|
15
21
|
from contentctl.objects.lookup import Lookup
|
|
16
|
-
from contentctl.objects.constants import
|
|
22
|
+
from contentctl.objects.constants import (
|
|
23
|
+
CONTENTCTL_MAX_SEARCH_NAME_LENGTH,
|
|
24
|
+
CONTENTCTL_BASELINE_STANZA_NAME_FORMAT_TEMPLATE,
|
|
25
|
+
)
|
|
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)
|
|
@@ -26,30 +36,31 @@ class Baseline(SecurityContentObject):
|
|
|
26
36
|
# enrichment
|
|
27
37
|
deployment: Deployment = Field({})
|
|
28
38
|
|
|
29
|
-
|
|
30
|
-
@field_validator('lookups', mode="before")
|
|
39
|
+
@field_validator("lookups", mode="before")
|
|
31
40
|
@classmethod
|
|
32
|
-
def getBaselineLookups(cls, v:list[str], info:ValidationInfo) -> list[Lookup]:
|
|
33
|
-
|
|
41
|
+
def getBaselineLookups(cls, v: list[str], info: ValidationInfo) -> list[Lookup]:
|
|
42
|
+
"""
|
|
34
43
|
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)
|
|
44
|
+
"""
|
|
45
|
+
director: DirectorOutputDto = info.context.get("output_dto", None)
|
|
46
|
+
search: str | None = info.data.get("search", None)
|
|
38
47
|
if search is None:
|
|
39
48
|
raise ValueError("Search was None - is this file missing the search field?")
|
|
40
|
-
|
|
49
|
+
|
|
41
50
|
lookups = Lookup.get_lookups(search, director)
|
|
42
51
|
return lookups
|
|
43
52
|
|
|
44
|
-
def get_conf_stanza_name(self, app:CustomApp)->str:
|
|
45
|
-
stanza_name = CONTENTCTL_BASELINE_STANZA_NAME_FORMAT_TEMPLATE.format(
|
|
53
|
+
def get_conf_stanza_name(self, app: CustomApp) -> str:
|
|
54
|
+
stanza_name = CONTENTCTL_BASELINE_STANZA_NAME_FORMAT_TEMPLATE.format(
|
|
55
|
+
app_label=app.label, detection_name=self.name
|
|
56
|
+
)
|
|
46
57
|
self.check_conf_stanza_max_length(stanza_name)
|
|
47
58
|
return stanza_name
|
|
48
59
|
|
|
49
60
|
@field_validator("deployment", mode="before")
|
|
50
|
-
def getDeployment(cls, v:Any, info:ValidationInfo)->Deployment:
|
|
51
|
-
return Deployment.getDeployment(v,info)
|
|
52
|
-
|
|
61
|
+
def getDeployment(cls, v: Any, info: ValidationInfo) -> Deployment:
|
|
62
|
+
return Deployment.getDeployment(v, info)
|
|
63
|
+
|
|
53
64
|
@computed_field
|
|
54
65
|
@property
|
|
55
66
|
def datamodel(self) -> List[DataModel]:
|
|
@@ -57,21 +68,21 @@ class Baseline(SecurityContentObject):
|
|
|
57
68
|
|
|
58
69
|
@model_serializer
|
|
59
70
|
def serialize_model(self):
|
|
60
|
-
#Call serializer for parent
|
|
71
|
+
# Call serializer for parent
|
|
61
72
|
super_fields = super().serialize_model()
|
|
62
|
-
|
|
63
|
-
#All fields custom to this model
|
|
64
|
-
model= {
|
|
73
|
+
|
|
74
|
+
# All fields custom to this model
|
|
75
|
+
model = {
|
|
65
76
|
"tags": self.tags.model_dump(),
|
|
66
77
|
"type": self.type,
|
|
67
78
|
"search": self.search,
|
|
68
|
-
"how_to_implement":self.how_to_implement,
|
|
69
|
-
"known_false_positives":self.known_false_positives,
|
|
79
|
+
"how_to_implement": self.how_to_implement,
|
|
80
|
+
"known_false_positives": self.known_false_positives,
|
|
70
81
|
"datamodel": self.datamodel,
|
|
71
82
|
}
|
|
72
|
-
|
|
73
|
-
#Combine fields from this model with fields from parent
|
|
83
|
+
|
|
84
|
+
# Combine fields from this model with fields from parent
|
|
74
85
|
super_fields.update(model)
|
|
75
|
-
|
|
76
|
-
#return the model
|
|
77
|
-
return super_fields
|
|
86
|
+
|
|
87
|
+
# return the model
|
|
88
|
+
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
|