contentctl 5.0.2__tar.gz → 5.0.3__tar.gz
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-5.0.2 → contentctl-5.0.3}/PKG-INFO +1 -1
- contentctl-5.0.3/contentctl/objects/annotated_types.py +9 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/detection_tags.py +57 -4
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/mitre_attack_enrichment.py +16 -3
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/story_tags.py +6 -5
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/detections/endpoint/anomalous_usage_of_7zip.yml +0 -1
- {contentctl-5.0.2 → contentctl-5.0.3}/pyproject.toml +1 -1
- contentctl-5.0.2/contentctl/objects/annotated_types.py +0 -6
- {contentctl-5.0.2 → contentctl-5.0.3}/LICENSE.md +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/README.md +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/__init__.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/build.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/deploy_acs.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/detection_testing/DetectionTestingManager.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/detection_testing/GitService.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/detection_testing/generate_detection_coverage_badge.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructure.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructureContainer.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructureServer.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/detection_testing/progress_bar.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/detection_testing/views/DetectionTestingView.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/detection_testing/views/DetectionTestingViewCLI.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/detection_testing/views/DetectionTestingViewFile.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/detection_testing/views/DetectionTestingViewWeb.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/doc_gen.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/initialize.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/inspect.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/new_content.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/release_notes.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/reporting.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/test.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/actions/validate.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/api.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/contentctl.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/enrichments/attack_enrichment.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/enrichments/cve_enrichment.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/enrichments/splunk_app_enrichment.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/helper/link_validator.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/helper/logger.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/helper/splunk_app.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/helper/utils.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/input/director.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/input/new_content_questions.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/input/yml_reader.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/abstract_security_content_objects/detection_abstract.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/abstract_security_content_objects/security_content_object_abstract.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/alert_action.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/atomic.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/base_test.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/base_test_result.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/baseline.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/baseline_tags.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/config.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/constants.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/correlation_search.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/dashboard.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/data_source.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/deployment.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/deployment_email.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/deployment_notable.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/deployment_phantom.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/deployment_rba.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/deployment_scheduling.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/deployment_slack.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/detection.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/detection_metadata.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/detection_stanza.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/drilldown.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/enums.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/errors.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/integration_test.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/integration_test_result.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/investigation.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/investigation_tags.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/lookup.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/macro.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/manual_test.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/manual_test_result.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/notable_action.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/notable_event.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/playbook.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/playbook_tags.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/rba.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/risk_analysis_action.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/risk_event.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/risk_object.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/savedsearches_conf.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/security_content_object.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/story.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/test_attack_data.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/test_group.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/threat_object.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/throttling.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/unit_test.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/unit_test_baseline.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/objects/unit_test_result.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/api_json_output.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/attack_nav_output.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/attack_nav_writer.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/conf_output.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/conf_writer.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/data_source_writer.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/doc_md_output.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/jinja_writer.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/json_writer.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/svg_output.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/analyticstories_detections.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/analyticstories_investigations.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/analyticstories_stories.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/app.conf.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/app.manifest.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/collections.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/content-version.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/detection_count.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/detection_coverage.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/doc_detection_page.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/doc_detections.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/doc_navigation.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/doc_navigation_pages.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/doc_playbooks.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/doc_playbooks_page.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/doc_stories.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/doc_story_page.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/es_investigations_investigations.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/es_investigations_stories.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/header.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/macros.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/panel.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/savedsearches_baselines.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/savedsearches_detections.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/savedsearches_investigations.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/server.conf.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/transforms.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/workflow_actions.j2 +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/yml_writer.py +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/README.md +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_default.yml +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/README/essoc_story_detail.txt +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/README/essoc_summary.txt +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/README/essoc_usage_dashboard.txt +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/README.md +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/default/analytic_stories.conf +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/default/commands.conf +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/default/data/ui/nav/default.xml +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/default/data/ui/views/escu_summary.xml +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/default/data/ui/views/feedback.xml +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/default/use_case_library.conf +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/lookups/mitre_enrichment.csv +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/metadata/default.meta +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/static/appIcon.png +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/static/appIconAlt.png +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/static/appIconAlt_2x.png +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/static/appIcon_2x.png +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/data_sources/sysmon_eventid_1.yml +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/datamodels_cim.conf +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/datamodels_custom.conf +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/deployments/escu_default_configuration_anomaly.yml +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/deployments/escu_default_configuration_baseline.yml +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/deployments/escu_default_configuration_correlation.yml +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/deployments/escu_default_configuration_hunting.yml +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/deployments/escu_default_configuration_ttp.yml +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/detections/application/.gitkeep +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/detections/cloud/.gitkeep +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/detections/network/.gitkeep +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/detections/web/.gitkeep +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/macros/security_content_ctime.yml +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/macros/security_content_summariesonly.yml +0 -0
- {contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/stories/cobalt_strike.yml +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
|
|
5
|
+
CVE_TYPE = Annotated[str, Field(pattern=r"^CVE-[1|2]\d{3}-\d+$")]
|
|
6
|
+
MITRE_ATTACK_ID_TYPE_PARENT = Annotated[str, Field(pattern=r"^T\d{4}$")]
|
|
7
|
+
MITRE_ATTACK_ID_TYPE_SUBTYPE = Annotated[str, Field(pattern=r"^T\d{4}(.\d{3})$")]
|
|
8
|
+
MITRE_ATTACK_ID_TYPE = MITRE_ATTACK_ID_TYPE_PARENT | MITRE_ATTACK_ID_TYPE_SUBTYPE
|
|
9
|
+
APPID_TYPE = Annotated[str, Field(pattern="^[a-zA-Z0-9_-]+$")]
|
|
@@ -33,7 +33,10 @@ from contentctl.objects.enums import (
|
|
|
33
33
|
SecurityContentProductName,
|
|
34
34
|
SecurityDomain,
|
|
35
35
|
)
|
|
36
|
-
from contentctl.objects.mitre_attack_enrichment import
|
|
36
|
+
from contentctl.objects.mitre_attack_enrichment import (
|
|
37
|
+
MitreAttackEnrichment,
|
|
38
|
+
MitreAttackGroup,
|
|
39
|
+
)
|
|
37
40
|
|
|
38
41
|
|
|
39
42
|
class DetectionTags(BaseModel):
|
|
@@ -44,7 +47,7 @@ class DetectionTags(BaseModel):
|
|
|
44
47
|
asset_type: AssetType = Field(...)
|
|
45
48
|
group: list[str] = []
|
|
46
49
|
|
|
47
|
-
mitre_attack_id:
|
|
50
|
+
mitre_attack_id: list[MITRE_ATTACK_ID_TYPE] = []
|
|
48
51
|
nist: list[NistCategory] = []
|
|
49
52
|
|
|
50
53
|
product: list[SecurityContentProductName] = Field(..., min_length=1)
|
|
@@ -68,6 +71,15 @@ class DetectionTags(BaseModel):
|
|
|
68
71
|
phases.add(phase)
|
|
69
72
|
return sorted(list(phases))
|
|
70
73
|
|
|
74
|
+
# We do not want this to be included in serialization. By default, @property
|
|
75
|
+
# objects are not included in dumps
|
|
76
|
+
@property
|
|
77
|
+
def unique_mitre_attack_groups(self) -> list[MitreAttackGroup]:
|
|
78
|
+
group_set: set[MitreAttackGroup] = set()
|
|
79
|
+
for enrichment in self.mitre_attack_enrichments:
|
|
80
|
+
group_set.update(set(enrichment.mitre_attack_group_objects))
|
|
81
|
+
return sorted(group_set, key=lambda k: k.group)
|
|
82
|
+
|
|
71
83
|
# enum is intentionally Cis18 even though field is named cis20 for legacy reasons
|
|
72
84
|
@computed_field
|
|
73
85
|
@property
|
|
@@ -134,8 +146,8 @@ class DetectionTags(BaseModel):
|
|
|
134
146
|
|
|
135
147
|
if len(missing_tactics) > 0:
|
|
136
148
|
raise ValueError(f"Missing Mitre Attack IDs. {missing_tactics} not found.")
|
|
137
|
-
|
|
138
|
-
|
|
149
|
+
|
|
150
|
+
self.mitre_attack_enrichments = mitre_enrichments
|
|
139
151
|
|
|
140
152
|
return self
|
|
141
153
|
|
|
@@ -159,6 +171,44 @@ class DetectionTags(BaseModel):
|
|
|
159
171
|
return enrichments
|
|
160
172
|
"""
|
|
161
173
|
|
|
174
|
+
@field_validator("mitre_attack_id", mode="after")
|
|
175
|
+
@classmethod
|
|
176
|
+
def sameTypeAndSubtypeNotPresent(
|
|
177
|
+
cls, techniques_and_subtechniques: list[MITRE_ATTACK_ID_TYPE]
|
|
178
|
+
) -> list[MITRE_ATTACK_ID_TYPE]:
|
|
179
|
+
techniques: list[str] = [
|
|
180
|
+
f"{unknown_technique}."
|
|
181
|
+
for unknown_technique in techniques_and_subtechniques
|
|
182
|
+
if "." not in unknown_technique
|
|
183
|
+
]
|
|
184
|
+
subtechniques: list[MITRE_ATTACK_ID_TYPE] = [
|
|
185
|
+
unknown_technique
|
|
186
|
+
for unknown_technique in techniques_and_subtechniques
|
|
187
|
+
if "." in unknown_technique
|
|
188
|
+
]
|
|
189
|
+
subtype_and_parent_exist_exceptions: list[ValueError] = []
|
|
190
|
+
|
|
191
|
+
for subtechnique in subtechniques:
|
|
192
|
+
for technique in techniques:
|
|
193
|
+
if subtechnique.startswith(technique):
|
|
194
|
+
subtype_and_parent_exist_exceptions.append(
|
|
195
|
+
ValueError(
|
|
196
|
+
f" Technique : {technique.split('.')[0]}\n"
|
|
197
|
+
f" SubTechnique: {subtechnique}\n"
|
|
198
|
+
)
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
if len(subtype_and_parent_exist_exceptions):
|
|
202
|
+
error_string = "\n".join(
|
|
203
|
+
str(e) for e in subtype_and_parent_exist_exceptions
|
|
204
|
+
)
|
|
205
|
+
raise ValueError(
|
|
206
|
+
"Overlapping MITRE Attack ID Techniques and Subtechniques may not be defined. "
|
|
207
|
+
f"Remove the Technique and keep the Subtechnique:\n{error_string}"
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
return techniques_and_subtechniques
|
|
211
|
+
|
|
162
212
|
@field_validator("analytic_story", mode="before")
|
|
163
213
|
@classmethod
|
|
164
214
|
def mapStoryNamesToStoryObjects(
|
|
@@ -238,3 +288,6 @@ class DetectionTags(BaseModel):
|
|
|
238
288
|
return matched_tests + [
|
|
239
289
|
AtomicTest.AtomicTestWhenTestIsMissing(test) for test in missing_tests
|
|
240
290
|
]
|
|
291
|
+
return matched_tests + [
|
|
292
|
+
AtomicTest.AtomicTestWhenTestIsMissing(test) for test in missing_tests
|
|
293
|
+
]
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import List
|
|
4
|
-
from enum import StrEnum
|
|
2
|
+
|
|
5
3
|
import datetime
|
|
4
|
+
from enum import StrEnum
|
|
5
|
+
from typing import List
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field, HttpUrl, field_validator
|
|
8
|
+
|
|
6
9
|
from contentctl.objects.annotated_types import MITRE_ATTACK_ID_TYPE
|
|
7
10
|
|
|
8
11
|
|
|
@@ -84,6 +87,16 @@ class MitreAttackGroup(BaseModel):
|
|
|
84
87
|
return []
|
|
85
88
|
return contributors
|
|
86
89
|
|
|
90
|
+
def __lt__(self, other: MitreAttackGroup) -> bool:
|
|
91
|
+
if not isinstance(object, MitreAttackGroup):
|
|
92
|
+
raise Exception(
|
|
93
|
+
f"Cannot compare object of type MitreAttackGroup to object of type [{type(object).__name__}]"
|
|
94
|
+
)
|
|
95
|
+
return self.group < other.group
|
|
96
|
+
|
|
97
|
+
def __hash__(self) -> int:
|
|
98
|
+
return hash(self.group)
|
|
99
|
+
|
|
87
100
|
|
|
88
101
|
class MitreAttackEnrichment(BaseModel):
|
|
89
102
|
ConfigDict(extra="forbid")
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from pydantic import BaseModel, Field, model_serializer, ConfigDict
|
|
3
|
-
from typing import List, Set, Optional
|
|
4
2
|
|
|
5
3
|
from enum import Enum
|
|
4
|
+
from typing import List, Optional, Set
|
|
6
5
|
|
|
7
|
-
from
|
|
6
|
+
from pydantic import BaseModel, ConfigDict, Field, model_serializer
|
|
7
|
+
|
|
8
|
+
from contentctl.objects.annotated_types import CVE_TYPE, MITRE_ATTACK_ID_TYPE
|
|
8
9
|
from contentctl.objects.enums import (
|
|
9
|
-
StoryCategory,
|
|
10
10
|
DataModel,
|
|
11
11
|
KillChainPhase,
|
|
12
12
|
SecurityContentProductName,
|
|
13
|
+
StoryCategory,
|
|
13
14
|
)
|
|
14
|
-
from contentctl.objects.
|
|
15
|
+
from contentctl.objects.mitre_attack_enrichment import MitreAttackEnrichment
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class StoryUseCase(str, Enum):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/analyticstories_detections.j2
RENAMED
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/analyticstories_investigations.j2
RENAMED
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/analyticstories_stories.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/es_investigations_stories.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/savedsearches_baselines.j2
RENAMED
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/savedsearches_detections.j2
RENAMED
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/output/templates/savedsearches_investigations.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/README/essoc_summary.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/default/commands.conf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/lookups/mitre_enrichment.csv
RENAMED
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/metadata/default.meta
RENAMED
|
File without changes
|
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/static/appIconAlt.png
RENAMED
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/static/appIconAlt_2x.png
RENAMED
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/app_template/static/appIcon_2x.png
RENAMED
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/data_sources/sysmon_eventid_1.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/macros/security_content_ctime.yml
RENAMED
|
File without changes
|
{contentctl-5.0.2 → contentctl-5.0.3}/contentctl/templates/macros/security_content_summariesonly.yml
RENAMED
|
File without changes
|
|
File without changes
|