contentctl 3.6.0__py3-none-any.whl → 4.0.2__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 +89 -0
- contentctl/actions/detection_testing/DetectionTestingManager.py +48 -49
- contentctl/actions/detection_testing/GitService.py +148 -230
- contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructure.py +14 -24
- contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructureContainer.py +43 -17
- contentctl/actions/detection_testing/views/DetectionTestingView.py +3 -2
- contentctl/actions/detection_testing/views/DetectionTestingViewFile.py +0 -8
- contentctl/actions/doc_gen.py +1 -1
- contentctl/actions/initialize.py +28 -65
- contentctl/actions/inspect.py +260 -0
- contentctl/actions/new_content.py +106 -13
- contentctl/actions/release_notes.py +168 -144
- contentctl/actions/reporting.py +24 -13
- contentctl/actions/test.py +39 -20
- contentctl/actions/validate.py +25 -48
- contentctl/contentctl.py +196 -754
- contentctl/enrichments/attack_enrichment.py +69 -19
- contentctl/enrichments/cve_enrichment.py +28 -13
- contentctl/helper/link_validator.py +24 -26
- contentctl/helper/utils.py +7 -3
- contentctl/input/director.py +139 -201
- contentctl/input/new_content_questions.py +63 -61
- contentctl/input/sigma_converter.py +1 -2
- contentctl/input/ssa_detection_builder.py +16 -7
- contentctl/input/yml_reader.py +4 -3
- contentctl/objects/abstract_security_content_objects/detection_abstract.py +487 -154
- contentctl/objects/abstract_security_content_objects/security_content_object_abstract.py +155 -51
- contentctl/objects/alert_action.py +40 -0
- contentctl/objects/atomic.py +212 -0
- contentctl/objects/baseline.py +44 -43
- contentctl/objects/baseline_tags.py +69 -20
- contentctl/objects/config.py +857 -125
- contentctl/objects/constants.py +0 -1
- contentctl/objects/correlation_search.py +1 -1
- contentctl/objects/data_source.py +2 -4
- contentctl/objects/deployment.py +61 -21
- contentctl/objects/deployment_email.py +2 -2
- contentctl/objects/deployment_notable.py +4 -4
- contentctl/objects/deployment_phantom.py +2 -2
- contentctl/objects/deployment_rba.py +3 -4
- contentctl/objects/deployment_scheduling.py +2 -3
- contentctl/objects/deployment_slack.py +2 -2
- contentctl/objects/detection.py +1 -5
- contentctl/objects/detection_tags.py +210 -119
- contentctl/objects/enums.py +312 -24
- contentctl/objects/integration_test.py +1 -1
- contentctl/objects/integration_test_result.py +0 -2
- contentctl/objects/investigation.py +62 -53
- contentctl/objects/investigation_tags.py +30 -6
- contentctl/objects/lookup.py +80 -31
- contentctl/objects/macro.py +29 -45
- contentctl/objects/mitre_attack_enrichment.py +29 -5
- contentctl/objects/observable.py +3 -7
- contentctl/objects/playbook.py +60 -30
- contentctl/objects/playbook_tags.py +45 -8
- contentctl/objects/security_content_object.py +1 -5
- contentctl/objects/ssa_detection.py +8 -4
- contentctl/objects/ssa_detection_tags.py +19 -26
- contentctl/objects/story.py +142 -44
- contentctl/objects/story_tags.py +46 -33
- contentctl/objects/unit_test.py +7 -2
- contentctl/objects/unit_test_attack_data.py +10 -19
- contentctl/objects/unit_test_baseline.py +1 -1
- contentctl/objects/unit_test_old.py +4 -3
- contentctl/objects/unit_test_result.py +5 -3
- contentctl/objects/unit_test_ssa.py +31 -0
- contentctl/output/api_json_output.py +202 -130
- contentctl/output/attack_nav_output.py +20 -9
- contentctl/output/attack_nav_writer.py +3 -3
- contentctl/output/ba_yml_output.py +3 -3
- contentctl/output/conf_output.py +125 -391
- contentctl/output/conf_writer.py +169 -31
- contentctl/output/jinja_writer.py +2 -2
- contentctl/output/json_writer.py +17 -5
- contentctl/output/new_content_yml_output.py +8 -7
- contentctl/output/svg_output.py +17 -27
- contentctl/output/templates/analyticstories_detections.j2 +8 -4
- contentctl/output/templates/analyticstories_investigations.j2 +1 -1
- contentctl/output/templates/analyticstories_stories.j2 +6 -6
- contentctl/output/templates/app.conf.j2 +2 -2
- contentctl/output/templates/app.manifest.j2 +2 -2
- contentctl/output/templates/detection_coverage.j2 +6 -8
- contentctl/output/templates/doc_detection_page.j2 +2 -2
- contentctl/output/templates/doc_detections.j2 +2 -2
- contentctl/output/templates/doc_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/header.j2 +2 -1
- contentctl/output/templates/macros.j2 +6 -10
- contentctl/output/templates/savedsearches_baselines.j2 +5 -5
- contentctl/output/templates/savedsearches_detections.j2 +36 -33
- contentctl/output/templates/savedsearches_investigations.j2 +4 -4
- contentctl/output/templates/transforms.j2 +4 -4
- contentctl/output/yml_writer.py +2 -2
- contentctl/templates/app_template/README.md +7 -0
- contentctl/{output/templates/splunk_app → templates/app_template}/default/data/ui/nav/default.xml +1 -0
- contentctl/templates/app_template/lookups/mitre_enrichment.csv +638 -0
- contentctl/templates/deployments/{00_default_anomaly.yml → escu_default_configuration_anomaly.yml} +1 -2
- contentctl/templates/deployments/{00_default_baseline.yml → escu_default_configuration_baseline.yml} +1 -2
- contentctl/templates/deployments/{00_default_correlation.yml → escu_default_configuration_correlation.yml} +2 -2
- contentctl/templates/deployments/{00_default_hunting.yml → escu_default_configuration_hunting.yml} +2 -2
- contentctl/templates/deployments/{00_default_ttp.yml → escu_default_configuration_ttp.yml} +1 -2
- contentctl/templates/detections/anomalous_usage_of_7zip.yml +0 -1
- contentctl/templates/stories/cobalt_strike.yml +0 -1
- {contentctl-3.6.0.dist-info → contentctl-4.0.2.dist-info}/METADATA +36 -15
- contentctl-4.0.2.dist-info/RECORD +168 -0
- contentctl/actions/detection_testing/DataManipulation.py +0 -149
- contentctl/actions/generate.py +0 -91
- contentctl/helper/config_handler.py +0 -75
- contentctl/input/baseline_builder.py +0 -66
- contentctl/input/basic_builder.py +0 -58
- contentctl/input/detection_builder.py +0 -370
- contentctl/input/investigation_builder.py +0 -42
- contentctl/input/new_content_generator.py +0 -95
- contentctl/input/playbook_builder.py +0 -68
- contentctl/input/story_builder.py +0 -106
- contentctl/objects/app.py +0 -214
- contentctl/objects/repo_config.py +0 -163
- contentctl/objects/test_config.py +0 -630
- contentctl/output/templates/macros_detections.j2 +0 -7
- contentctl/output/templates/splunk_app/README.md +0 -7
- contentctl-3.6.0.dist-info/RECORD +0 -176
- /contentctl/{output/templates/splunk_app → templates/app_template}/README/essoc_story_detail.txt +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/README/essoc_summary.txt +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/README/essoc_usage_dashboard.txt +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/default/analytic_stories.conf +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/default/app.conf +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/default/commands.conf +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/default/content-version.conf +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/default/data/ui/views/escu_summary.xml +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/default/data/ui/views/feedback.xml +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/default/distsearch.conf +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/default/usage_searches.conf +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/default/use_case_library.conf +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/metadata/default.meta +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/static/appIcon.png +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/static/appIconAlt.png +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/static/appIconAlt_2x.png +0 -0
- /contentctl/{output/templates/splunk_app → templates/app_template}/static/appIcon_2x.png +0 -0
- {contentctl-3.6.0.dist-info → contentctl-4.0.2.dist-info}/LICENSE.md +0 -0
- {contentctl-3.6.0.dist-info → contentctl-4.0.2.dist-info}/WHEEL +0 -0
- {contentctl-3.6.0.dist-info → contentctl-4.0.2.dist-info}/entry_points.txt +0 -0
|
@@ -6,22 +6,22 @@
|
|
|
6
6
|
action.escu = 0
|
|
7
7
|
action.escu.enabled = 1
|
|
8
8
|
{% if detection.status == "deprecated" %}
|
|
9
|
-
description = **WARNING**, this detection 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. {{ detection.description }}
|
|
9
|
+
description = **WARNING**, this detection 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. {{ detection.description | escapeNewlines() }}
|
|
10
10
|
{% elif detection.status == "experimental" %}
|
|
11
|
-
description = **WARNING**, this detection is marked **EXPERIMENTAL** by the Splunk Threat Research Team. This means that the detection 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. {{ detection.description }}
|
|
11
|
+
description = **WARNING**, this detection is marked **EXPERIMENTAL** by the Splunk Threat Research Team. This means that the detection 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. {{ detection.description | escapeNewlines() }}
|
|
12
12
|
{% else %}
|
|
13
|
-
description = {{ detection.description }}
|
|
13
|
+
description = {{ detection.description | escapeNewlines() }}
|
|
14
14
|
{% endif %}
|
|
15
15
|
action.escu.mappings = {{ detection.mappings | tojson }}
|
|
16
16
|
action.escu.data_models = {{ detection.datamodel | tojson }}
|
|
17
|
-
action.escu.eli5 = {{ detection.description }}
|
|
18
|
-
{% if detection.how_to_implement
|
|
19
|
-
action.escu.how_to_implement = {{ detection.how_to_implement }}
|
|
17
|
+
action.escu.eli5 = {{ detection.description | escapeNewlines() }}
|
|
18
|
+
{% if detection.how_to_implement %}
|
|
19
|
+
action.escu.how_to_implement = {{ detection.how_to_implement | escapeNewlines() }}
|
|
20
20
|
{% else %}
|
|
21
21
|
action.escu.how_to_implement = none
|
|
22
22
|
{% endif %}
|
|
23
|
-
{% if detection.known_false_positives
|
|
24
|
-
action.escu.known_false_positives = {{ detection.known_false_positives }}
|
|
23
|
+
{% if detection.known_false_positives %}
|
|
24
|
+
action.escu.known_false_positives = {{ detection.known_false_positives | escapeNewlines() }}
|
|
25
25
|
{% else %}
|
|
26
26
|
action.escu.known_false_positives = None
|
|
27
27
|
{% endif %}
|
|
@@ -33,16 +33,19 @@ action.escu.search_type = detection
|
|
|
33
33
|
{% if detection.tags.product is defined %}
|
|
34
34
|
action.escu.product = {{ detection.tags.product | tojson }}
|
|
35
35
|
{% endif %}
|
|
36
|
-
{% if detection.
|
|
36
|
+
{% if detection.tags.atomic_guid %}
|
|
37
|
+
action.escu.atomic_red_team_guids = {{ detection.tags.getAtomicGuidStringArray() | tojson }}
|
|
38
|
+
{% endif %}
|
|
39
|
+
{% if detection.providing_technologies | length > 0 %}
|
|
37
40
|
action.escu.providing_technologies = {{ detection.providing_technologies | tojson }}
|
|
38
41
|
{% else %}
|
|
39
|
-
action.escu.providing_technologies =
|
|
42
|
+
action.escu.providing_technologies = null
|
|
40
43
|
{% endif %}
|
|
41
|
-
{% if detection.tags.analytic_story
|
|
42
|
-
action.escu.analytic_story = {{ detection.tags.analytic_story | tojson }}
|
|
43
|
-
{% if detection.deployment.rba.enabled
|
|
44
|
+
{% if detection.tags.analytic_story %}
|
|
45
|
+
action.escu.analytic_story = {{ objectListToNameList(detection.tags.analytic_story) | tojson }}
|
|
46
|
+
{% if detection.deployment.alert_action.rba.enabled%}
|
|
44
47
|
action.risk = 1
|
|
45
|
-
action.risk.param._risk_message = {{ detection.tags.message }}
|
|
48
|
+
action.risk.param._risk_message = {{ detection.tags.message | escapeNewlines() }}
|
|
46
49
|
action.risk.param._risk = {{ detection.risk | tojson }}
|
|
47
50
|
action.risk.param._risk_score = 0
|
|
48
51
|
action.risk.param.verbose = 0
|
|
@@ -69,34 +72,34 @@ action.correlationsearch.metadata = {{ detection.getMetadata() | tojson }}
|
|
|
69
72
|
schedule_window = {{ detection.deployment.scheduling.schedule_window }}
|
|
70
73
|
{% endif %}
|
|
71
74
|
{% if detection.deployment is defined %}
|
|
72
|
-
{% if detection.deployment.notable
|
|
75
|
+
{% if detection.deployment.alert_action.notable %}
|
|
73
76
|
action.notable = 1
|
|
74
|
-
{% if detection.nes_fields
|
|
77
|
+
{% if detection.nes_fields %}
|
|
75
78
|
action.notable.param.nes_fields = {{ detection.nes_fields }}
|
|
76
79
|
{% endif %}
|
|
77
|
-
action.notable.param.rule_description = {{ detection.deployment.notable.rule_description | custom_jinja2_enrichment_filter(detection) }}
|
|
78
|
-
action.notable.param.rule_title = {% if detection.type | lower == "correlation" %}RBA: {{ detection.deployment.notable.rule_title | custom_jinja2_enrichment_filter(detection) }}{% else %}{{ detection.deployment.notable.rule_title | custom_jinja2_enrichment_filter(detection) }}{% endif +%}
|
|
79
|
-
action.notable.param.security_domain = {{ detection.tags.security_domain }}
|
|
80
|
+
action.notable.param.rule_description = {{ detection.deployment.alert_action.notable.rule_description | custom_jinja2_enrichment_filter(detection) | escapeNewlines()}}
|
|
81
|
+
action.notable.param.rule_title = {% if detection.type | lower == "correlation" %}RBA: {{ detection.deployment.alert_action.notable.rule_title | custom_jinja2_enrichment_filter(detection) }}{% else %}{{ detection.deployment.alert_action.notable.rule_title | custom_jinja2_enrichment_filter(detection) }}{% endif +%}
|
|
82
|
+
action.notable.param.security_domain = {{ detection.tags.security_domain.value }}
|
|
80
83
|
action.notable.param.severity = high
|
|
81
84
|
{% endif %}
|
|
82
|
-
{% if detection.deployment.email
|
|
83
|
-
action.email.subject.alert = {{ detection.deployment.email.subject | custom_jinja2_enrichment_filter(detection) }}
|
|
84
|
-
action.email.to = {{ detection.deployment.email.to }}
|
|
85
|
-
action.email.message.alert = {{ detection.deployment.email.message | custom_jinja2_enrichment_filter(detection) }}
|
|
85
|
+
{% if detection.deployment.alert_action.email %}
|
|
86
|
+
action.email.subject.alert = {{ detection.deployment.alert_action.email.subject | custom_jinja2_enrichment_filter(detection) | escapeNewlines() }}
|
|
87
|
+
action.email.to = {{ detection.deployment.alert_action.email.to }}
|
|
88
|
+
action.email.message.alert = {{ detection.deployment.alert_action.email.message | custom_jinja2_enrichment_filter(detection) | escapeNewlines() }}
|
|
86
89
|
action.email.useNSSubject = 1
|
|
87
90
|
{% endif %}
|
|
88
|
-
{% if detection.deployment.slack
|
|
91
|
+
{% if detection.deployment.alert_action.slack %}
|
|
89
92
|
action.slack = 1
|
|
90
|
-
action.slack.param.channel = {{ detection.deployment.slack.channel | custom_jinja2_enrichment_filter(detection) }}
|
|
91
|
-
action.slack.param.message = {{ detection.deployment.slack.message | custom_jinja2_enrichment_filter(detection) }}
|
|
93
|
+
action.slack.param.channel = {{ detection.deployment.alert_action.slack.channel | custom_jinja2_enrichment_filter(detection) | escapeNewlines() }}
|
|
94
|
+
action.slack.param.message = {{ detection.deployment.alert_action.slack.message | custom_jinja2_enrichment_filter(detection) | escapeNewlines() }}
|
|
92
95
|
{% endif %}
|
|
93
|
-
{% if detection.deployment.phantom
|
|
96
|
+
{% if detection.deployment.alert_action.phantom%}
|
|
94
97
|
action.sendtophantom = 1
|
|
95
|
-
action.sendtophantom.param._cam_workers = {{ detection.deployment.phantom.cam_workers | custom_jinja2_enrichment_filter(detection) }}
|
|
96
|
-
action.sendtophantom.param.label = {{ detection.deployment.phantom.label | custom_jinja2_enrichment_filter(detection) }}
|
|
97
|
-
action.sendtophantom.param.phantom_server = {{ detection.deployment.phantom.phantom_server | custom_jinja2_enrichment_filter(detection) }}
|
|
98
|
-
action.sendtophantom.param.sensitivity = {{ detection.deployment.phantom.sensitivity | custom_jinja2_enrichment_filter(detection) }}
|
|
99
|
-
action.sendtophantom.param.severity = {{ detection.deployment.phantom.severity | custom_jinja2_enrichment_filter(detection) }}
|
|
98
|
+
action.sendtophantom.param._cam_workers = {{ detection.deployment.alert_action.phantom.cam_workers | custom_jinja2_enrichment_filter(detection) }}
|
|
99
|
+
action.sendtophantom.param.label = {{ detection.deployment.alert_action.phantom.label | custom_jinja2_enrichment_filter(detection) }}
|
|
100
|
+
action.sendtophantom.param.phantom_server = {{ detection.deployment.alert_action.phantom.phantom_server | custom_jinja2_enrichment_filter(detection) }}
|
|
101
|
+
action.sendtophantom.param.sensitivity = {{ detection.deployment.alert_action.phantom.sensitivity | custom_jinja2_enrichment_filter(detection) }}
|
|
102
|
+
action.sendtophantom.param.severity = {{ detection.deployment.alert_action.phantom.severity | custom_jinja2_enrichment_filter(detection) }}
|
|
100
103
|
{% endif %}
|
|
101
104
|
{% endif %}
|
|
102
105
|
alert.digest_mode = 1
|
|
@@ -112,7 +115,7 @@ relation = greater than
|
|
|
112
115
|
quantity = 0
|
|
113
116
|
realtime_schedule = 0
|
|
114
117
|
is_visible = false
|
|
115
|
-
search = {{ detection.search }}
|
|
118
|
+
search = {{ detection.search | escapeNewlines() }}
|
|
116
119
|
|
|
117
120
|
{% endif %}
|
|
118
121
|
{% endfor %}
|
|
@@ -10,11 +10,11 @@ action.escu = 0
|
|
|
10
10
|
action.escu.enabled = 1
|
|
11
11
|
action.escu.search_type = investigative
|
|
12
12
|
action.escu.full_search_name = {{APP_NAME}} - {{ detection.name }} - Response Task
|
|
13
|
-
description = {{ detection.description }}
|
|
13
|
+
description = {{ detection.description | escapeNewlines() }}
|
|
14
14
|
action.escu.creation_date = {{ detection.date }}
|
|
15
15
|
action.escu.modification_date = {{ detection.date }}
|
|
16
16
|
{% if detection.tags.analytic_story is defined %}
|
|
17
|
-
action.escu.analytic_story = {{ detection.tags.analytic_story | tojson }}
|
|
17
|
+
action.escu.analytic_story = {{ objectListToNameList(detection.tags.analytic_story) | tojson }}
|
|
18
18
|
{% else %}
|
|
19
19
|
action.escu.analytic_story = []
|
|
20
20
|
{% endif %}
|
|
@@ -22,13 +22,13 @@ action.escu.earliest_time_offset = 3600
|
|
|
22
22
|
action.escu.latest_time_offset = 86400
|
|
23
23
|
action.escu.providing_technologies = []
|
|
24
24
|
action.escu.data_models = {{ detection.datamodel | tojson }}
|
|
25
|
-
action.escu.eli5 = {{ detection.description }}
|
|
25
|
+
action.escu.eli5 = {{ detection.description | escapeNewlines() }}
|
|
26
26
|
action.escu.how_to_implement = none
|
|
27
27
|
action.escu.known_false_positives = None at this time
|
|
28
28
|
disabled = true
|
|
29
29
|
schedule_window = auto
|
|
30
30
|
is_visible = false
|
|
31
|
-
search = {{ detection.search }}
|
|
31
|
+
search = {{ detection.search | escapeNewlines() }}
|
|
32
32
|
|
|
33
33
|
{% endif %}
|
|
34
34
|
{% endif %}
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
{% for lookup in objects %}
|
|
3
3
|
[{{ lookup.name }}]
|
|
4
4
|
{% if lookup.filename is defined and lookup.filename != None %}
|
|
5
|
-
filename = {{ lookup.filename }}
|
|
5
|
+
filename = {{ lookup.filename.name }}
|
|
6
6
|
{% else %}
|
|
7
7
|
collection = {{ lookup.collection }}
|
|
8
8
|
external_type = kvstore
|
|
9
9
|
{% endif %}
|
|
10
10
|
{% if lookup.default_match is defined and lookup.default_match != None %}
|
|
11
|
-
default_match = {{ lookup.default_match }}
|
|
11
|
+
default_match = {{ lookup.default_match | lower }}
|
|
12
12
|
{% endif %}
|
|
13
13
|
{% if lookup.case_sensitive_match is defined and lookup.case_sensitive_match != None %}
|
|
14
|
-
case_sensitive_match = {{ lookup.case_sensitive_match }}
|
|
14
|
+
case_sensitive_match = {{ lookup.case_sensitive_match | lower }}
|
|
15
15
|
{% endif %}
|
|
16
16
|
{% if lookup.description is defined and lookup.description != None %}
|
|
17
|
-
# description = {{ lookup.description }}
|
|
17
|
+
# description = {{ lookup.description | escapeNewlines() }}
|
|
18
18
|
{% endif %}
|
|
19
19
|
{% if lookup.match_type is defined and lookup.match_type != None %}
|
|
20
20
|
match_type = {{ lookup.match_type }}
|
contentctl/output/yml_writer.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
import yaml
|
|
3
|
-
|
|
3
|
+
from typing import Any
|
|
4
4
|
|
|
5
5
|
class YmlWriter:
|
|
6
6
|
|
|
7
7
|
@staticmethod
|
|
8
|
-
def writeYmlFile(file_path : str, obj : dict) -> None:
|
|
8
|
+
def writeYmlFile(file_path : str, obj : dict[Any,Any]) -> None:
|
|
9
9
|
|
|
10
10
|
with open(file_path, 'w') as outfile:
|
|
11
11
|
yaml.safe_dump(obj, outfile, default_flow_style=False, sort_keys=False)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Content Pack built with contentctl
|
|
2
|
+
|
|
3
|
+
This application was built using the open source [contentctl](https://github.com/splunk/contentctl) tool published by the Splunk Threat Research Team (STRT).
|
|
4
|
+
|
|
5
|
+
For questions about the tool, please see the repo or contact STRT at research@splunk.com
|
|
6
|
+
|
|
7
|
+
Feel free to update this file to include your own valuable README information.
|