contentctl 4.3.3__py3-none-any.whl → 4.3.5__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.
Files changed (36) hide show
  1. contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructure.py +0 -6
  2. contentctl/actions/initialize.py +28 -12
  3. contentctl/actions/inspect.py +189 -91
  4. contentctl/actions/validate.py +3 -7
  5. contentctl/api.py +1 -1
  6. contentctl/contentctl.py +3 -0
  7. contentctl/enrichments/attack_enrichment.py +51 -82
  8. contentctl/enrichments/cve_enrichment.py +2 -2
  9. contentctl/helper/splunk_app.py +141 -10
  10. contentctl/input/director.py +5 -12
  11. contentctl/objects/abstract_security_content_objects/detection_abstract.py +11 -8
  12. contentctl/objects/annotated_types.py +6 -0
  13. contentctl/objects/atomic.py +51 -77
  14. contentctl/objects/config.py +145 -22
  15. contentctl/objects/constants.py +4 -1
  16. contentctl/objects/correlation_search.py +35 -28
  17. contentctl/objects/detection_metadata.py +71 -0
  18. contentctl/objects/detection_stanza.py +79 -0
  19. contentctl/objects/detection_tags.py +11 -9
  20. contentctl/objects/enums.py +0 -2
  21. contentctl/objects/errors.py +187 -0
  22. contentctl/objects/mitre_attack_enrichment.py +2 -1
  23. contentctl/objects/risk_event.py +94 -76
  24. contentctl/objects/savedsearches_conf.py +196 -0
  25. contentctl/objects/story_tags.py +3 -3
  26. contentctl/output/conf_writer.py +4 -1
  27. contentctl/output/new_content_yml_output.py +4 -9
  28. {contentctl-4.3.3.dist-info → contentctl-4.3.5.dist-info}/METADATA +4 -4
  29. {contentctl-4.3.3.dist-info → contentctl-4.3.5.dist-info}/RECORD +32 -32
  30. contentctl/objects/ssa_detection.py +0 -157
  31. contentctl/objects/ssa_detection_tags.py +0 -138
  32. contentctl/objects/unit_test_old.py +0 -10
  33. contentctl/objects/unit_test_ssa.py +0 -31
  34. {contentctl-4.3.3.dist-info → contentctl-4.3.5.dist-info}/LICENSE.md +0 -0
  35. {contentctl-4.3.3.dist-info → contentctl-4.3.5.dist-info}/WHEEL +0 -0
  36. {contentctl-4.3.3.dist-info → contentctl-4.3.5.dist-info}/entry_points.txt +0 -0
@@ -1,138 +0,0 @@
1
- from __future__ import annotations
2
- import re
3
- from typing import List
4
- from pydantic import BaseModel, validator, ValidationError, model_validator, Field
5
-
6
- from contentctl.objects.mitre_attack_enrichment import MitreAttackEnrichment
7
- from contentctl.objects.constants import *
8
- from contentctl.objects.enums import SecurityContentProductName
9
-
10
- class SSADetectionTags(BaseModel):
11
- # detection spec
12
- #name: str
13
- analytic_story: list
14
- asset_type: str
15
- automated_detection_testing: str = None
16
- cis20: list = None
17
- confidence: int
18
- impact: int
19
- kill_chain_phases: list = None
20
- message: str
21
- mitre_attack_id: list = None
22
- nist: list = None
23
- observable: list
24
- product: List[SecurityContentProductName] = Field(...,min_length=1)
25
- required_fields: list
26
- risk_score: int
27
- security_domain: str
28
- risk_severity: str = None
29
- cve: list = None
30
- supported_tas: list = None
31
- atomic_guid: list = None
32
- drilldown_search: str = None
33
- manual_test: str = None
34
-
35
-
36
- # enrichment
37
- mitre_attack_enrichments: list[MitreAttackEnrichment] = []
38
- confidence_id: int = None
39
- impact_id: int = None
40
- context_ids: list = None
41
- risk_level_id: int = None
42
- risk_level: str = None
43
- observable_str: str = None
44
- evidence_str: str = None
45
- analytics_story_str: str = None
46
- kill_chain_phases_id:dict = None
47
- kill_chain_phases_str:str = None
48
- research_site_url: str = None
49
- event_schema: str = None
50
- mappings: list = None
51
- annotations: dict = None
52
-
53
-
54
- @validator('cis20')
55
- def tags_cis20(cls, v, values):
56
- pattern = r'^CIS ([\d|1\d|20)$' #DO NOT match leading zeroes and ensure no extra characters before or after the string
57
- for value in v:
58
- if not re.match(pattern, value):
59
- raise ValueError(f"CIS control '{value}' is not a valid Control ('CIS 1' -> 'CIS 20'): {values['name']}")
60
- return v
61
-
62
- @validator('nist')
63
- def tags_nist(cls, v, values):
64
- # Sourced Courtest of NIST: https://www.nist.gov/system/files/documents/cyberframework/cybersecurity-framework-021214.pdf (Page 19)
65
- IDENTIFY = [f'ID.{category}' for category in ["AM", "BE", "GV", "RA", "RM"] ]
66
- PROTECT = [f'PR.{category}' for category in ["AC", "AT", "DS", "IP", "MA", "PT"]]
67
- DETECT = [f'DE.{category}' for category in ["AE", "CM", "DP"] ]
68
- RESPOND = [f'RS.{category}' for category in ["RP", "CO", "AN", "MI", "IM"] ]
69
- RECOVER = [f'RC.{category}' for category in ["RP", "IM", "CO"] ]
70
- ALL_NIST_CATEGORIES = IDENTIFY + PROTECT + DETECT + RESPOND + RECOVER
71
-
72
-
73
- for value in v:
74
- if not value in ALL_NIST_CATEGORIES:
75
- raise ValueError(f"NIST Category '{value}' is not a valid category")
76
- return v
77
-
78
- @validator('confidence')
79
- def tags_confidence(cls, v, values):
80
- v = int(v)
81
- if not (v > 0 and v <= 100):
82
- raise ValueError('confidence score is out of range 1-100.' )
83
- else:
84
- return v
85
-
86
-
87
- @validator('impact')
88
- def tags_impact(cls, v, values):
89
- if not (v > 0 and v <= 100):
90
- raise ValueError('impact score is out of range 1-100.')
91
- else:
92
- return v
93
-
94
- @validator('kill_chain_phases')
95
- def tags_kill_chain_phases(cls, v, values):
96
- valid_kill_chain_phases = SES_KILL_CHAIN_MAPPINGS.keys()
97
- for value in v:
98
- if value not in valid_kill_chain_phases:
99
- raise ValueError('kill chain phase not valid. Valid options are ' + str(valid_kill_chain_phases))
100
- return v
101
-
102
- @validator('mitre_attack_id')
103
- def tags_mitre_attack_id(cls, v, values):
104
- pattern = 'T[0-9]{4}'
105
- for value in v:
106
- if not re.match(pattern, value):
107
- raise ValueError('Mitre Attack ID are not following the pattern Txxxx:' )
108
- return v
109
-
110
-
111
-
112
- @validator('risk_score')
113
- def tags_calculate_risk_score(cls, v, values):
114
- calculated_risk_score = round(values['impact'] * values['confidence'] / 100)
115
- if calculated_risk_score != int(v):
116
- raise ValueError(f"Risk Score must be calculated as round(confidence * impact / 100)"
117
- f"\n Expected risk_score={calculated_risk_score}, found risk_score={int(v)}: {values['name']}")
118
- return v
119
-
120
-
121
- @model_validator(mode="after")
122
- def tags_observable(self):
123
- valid_roles = SES_OBSERVABLE_ROLE_MAPPING.keys()
124
- valid_types = SES_OBSERVABLE_TYPE_MAPPING.keys()
125
-
126
- for value in self.observable:
127
- if value['type'] in valid_types:
128
- if 'Splunk Behavioral Analytics' in self.product:
129
- continue
130
-
131
- if 'role' not in value:
132
- raise ValueError('Observable role is missing')
133
- for role in value['role']:
134
- if role not in valid_roles:
135
- raise ValueError(f'Observable role ' + role + ' not valid. Valid options are {str(valid_roles)}')
136
- else:
137
- raise ValueError(f'Observable type ' + value['type'] + ' not valid. Valid options are {str(valid_types)}')
138
- return self
@@ -1,10 +0,0 @@
1
- from __future__ import annotations
2
- from pydantic import BaseModel
3
-
4
-
5
- from contentctl.objects.unit_test_ssa import UnitTestSSA
6
-
7
-
8
- class UnitTestOld(BaseModel):
9
- name: str
10
- tests: list[UnitTestSSA]
@@ -1,31 +0,0 @@
1
- from __future__ import annotations
2
- from typing import Optional
3
- from pydantic import BaseModel, Field
4
- from pydantic import Field
5
-
6
-
7
- class UnitTestAttackDataSSA(BaseModel):
8
- file_name:Optional[str] = None
9
- data: str = Field(...)
10
- # TODO - should source and sourcetype should be mapped to a list
11
- # of supported source and sourcetypes in a given environment?
12
- source: str = Field(...)
13
-
14
- sourcetype: Optional[str] = None
15
-
16
-
17
- class UnitTestSSA(BaseModel):
18
- """
19
- A unit test for a detection
20
- """
21
- name: str
22
-
23
- # The attack data to be ingested for the unit test
24
- attack_data: list[UnitTestAttackDataSSA] = Field(...)
25
-
26
-
27
-
28
-
29
-
30
-
31
-