contentctl 4.4.3__tar.gz → 4.4.4__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.
Files changed (176) hide show
  1. {contentctl-4.4.3 → contentctl-4.4.4}/PKG-INFO +1 -1
  2. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/build.py +3 -1
  3. contentctl-4.4.4/contentctl/actions/deploy_acs.py +55 -0
  4. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/contentctl.py +6 -2
  5. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/config.py +1 -0
  6. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/conf_output.py +14 -7
  7. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/conf_writer.py +117 -5
  8. contentctl-4.4.4/contentctl/output/templates/app.conf.j2 +37 -0
  9. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/app.manifest.j2 +2 -1
  10. contentctl-4.4.4/contentctl/output/templates/server.conf.j2 +4 -0
  11. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/metadata/default.meta +1 -1
  12. {contentctl-4.4.3 → contentctl-4.4.4}/pyproject.toml +1 -1
  13. contentctl-4.4.3/contentctl/actions/deploy_acs.py +0 -38
  14. contentctl-4.4.3/contentctl/output/templates/app.conf.j2 +0 -35
  15. contentctl-4.4.3/contentctl/templates/app_template/default/app.conf +0 -30
  16. contentctl-4.4.3/contentctl/templates/app_template/default/content-version.conf +0 -2
  17. {contentctl-4.4.3 → contentctl-4.4.4}/LICENSE.md +0 -0
  18. {contentctl-4.4.3 → contentctl-4.4.4}/README.md +0 -0
  19. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/__init__.py +0 -0
  20. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/detection_testing/DetectionTestingManager.py +0 -0
  21. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/detection_testing/GitService.py +0 -0
  22. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/detection_testing/generate_detection_coverage_badge.py +0 -0
  23. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructure.py +0 -0
  24. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructureContainer.py +0 -0
  25. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructureServer.py +0 -0
  26. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/detection_testing/progress_bar.py +0 -0
  27. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/detection_testing/views/DetectionTestingView.py +0 -0
  28. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/detection_testing/views/DetectionTestingViewCLI.py +0 -0
  29. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/detection_testing/views/DetectionTestingViewFile.py +0 -0
  30. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/detection_testing/views/DetectionTestingViewWeb.py +0 -0
  31. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/doc_gen.py +0 -0
  32. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/initialize.py +0 -0
  33. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/initialize_old.py +0 -0
  34. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/inspect.py +0 -0
  35. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/new_content.py +0 -0
  36. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/release_notes.py +0 -0
  37. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/reporting.py +0 -0
  38. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/test.py +0 -0
  39. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/actions/validate.py +0 -0
  40. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/api.py +0 -0
  41. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/enrichments/attack_enrichment.py +0 -0
  42. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/enrichments/cve_enrichment.py +0 -0
  43. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/enrichments/splunk_app_enrichment.py +0 -0
  44. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/helper/link_validator.py +0 -0
  45. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/helper/logger.py +0 -0
  46. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/helper/splunk_app.py +0 -0
  47. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/helper/utils.py +0 -0
  48. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/input/director.py +0 -0
  49. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/input/new_content_questions.py +0 -0
  50. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/input/yml_reader.py +0 -0
  51. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/abstract_security_content_objects/detection_abstract.py +0 -0
  52. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/abstract_security_content_objects/security_content_object_abstract.py +0 -0
  53. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/alert_action.py +0 -0
  54. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/annotated_types.py +0 -0
  55. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/atomic.py +0 -0
  56. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/base_test.py +0 -0
  57. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/base_test_result.py +0 -0
  58. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/baseline.py +0 -0
  59. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/baseline_tags.py +0 -0
  60. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/constants.py +0 -0
  61. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/correlation_search.py +0 -0
  62. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/dashboard.py +0 -0
  63. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/data_source.py +0 -0
  64. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/deployment.py +0 -0
  65. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/deployment_email.py +0 -0
  66. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/deployment_notable.py +0 -0
  67. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/deployment_phantom.py +0 -0
  68. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/deployment_rba.py +0 -0
  69. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/deployment_scheduling.py +0 -0
  70. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/deployment_slack.py +0 -0
  71. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/detection.py +0 -0
  72. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/detection_metadata.py +0 -0
  73. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/detection_stanza.py +0 -0
  74. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/detection_tags.py +0 -0
  75. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/drilldown.py +0 -0
  76. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/enums.py +0 -0
  77. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/errors.py +0 -0
  78. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/event_source.py +0 -0
  79. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/integration_test.py +0 -0
  80. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/integration_test_result.py +0 -0
  81. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/investigation.py +0 -0
  82. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/investigation_tags.py +0 -0
  83. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/lookup.py +0 -0
  84. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/macro.py +0 -0
  85. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/manual_test.py +0 -0
  86. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/manual_test_result.py +0 -0
  87. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/mitre_attack_enrichment.py +0 -0
  88. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/notable_action.py +0 -0
  89. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/notable_event.py +0 -0
  90. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/observable.py +0 -0
  91. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/playbook.py +0 -0
  92. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/playbook_tags.py +0 -0
  93. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/risk_analysis_action.py +0 -0
  94. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/risk_event.py +0 -0
  95. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/risk_object.py +0 -0
  96. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/savedsearches_conf.py +0 -0
  97. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/security_content_object.py +0 -0
  98. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/story.py +0 -0
  99. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/story_tags.py +0 -0
  100. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/test_attack_data.py +0 -0
  101. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/test_group.py +0 -0
  102. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/threat_object.py +0 -0
  103. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/throttling.py +0 -0
  104. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/unit_test.py +0 -0
  105. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/unit_test_baseline.py +0 -0
  106. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/objects/unit_test_result.py +0 -0
  107. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/api_json_output.py +0 -0
  108. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/attack_nav_output.py +0 -0
  109. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/attack_nav_writer.py +0 -0
  110. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/data_source_writer.py +0 -0
  111. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/detection_writer.py +0 -0
  112. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/doc_md_output.py +0 -0
  113. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/jinja_writer.py +0 -0
  114. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/json_writer.py +0 -0
  115. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/new_content_yml_output.py +0 -0
  116. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/svg_output.py +0 -0
  117. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/analyticstories_detections.j2 +0 -0
  118. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/analyticstories_investigations.j2 +0 -0
  119. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/analyticstories_stories.j2 +0 -0
  120. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/collections.j2 +0 -0
  121. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/content-version.j2 +0 -0
  122. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/detection_count.j2 +0 -0
  123. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/detection_coverage.j2 +0 -0
  124. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/doc_detection_page.j2 +0 -0
  125. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/doc_detections.j2 +0 -0
  126. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/doc_navigation.j2 +0 -0
  127. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/doc_navigation_pages.j2 +0 -0
  128. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/doc_playbooks.j2 +0 -0
  129. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/doc_playbooks_page.j2 +0 -0
  130. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/doc_stories.j2 +0 -0
  131. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/doc_story_page.j2 +0 -0
  132. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/es_investigations_investigations.j2 +0 -0
  133. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/es_investigations_stories.j2 +0 -0
  134. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/header.j2 +0 -0
  135. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/macros.j2 +0 -0
  136. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/panel.j2 +0 -0
  137. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/savedsearches_baselines.j2 +0 -0
  138. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/savedsearches_detections.j2 +0 -0
  139. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/savedsearches_investigations.j2 +0 -0
  140. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/transforms.j2 +0 -0
  141. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/templates/workflow_actions.j2 +0 -0
  142. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/yml_output.py +0 -0
  143. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/output/yml_writer.py +0 -0
  144. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/README.md +0 -0
  145. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_default.yml +0 -0
  146. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/README/essoc_story_detail.txt +0 -0
  147. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/README/essoc_summary.txt +0 -0
  148. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/README/essoc_usage_dashboard.txt +0 -0
  149. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/README.md +0 -0
  150. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/default/analytic_stories.conf +0 -0
  151. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/default/commands.conf +0 -0
  152. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/default/data/ui/nav/default.xml +0 -0
  153. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/default/data/ui/views/escu_summary.xml +0 -0
  154. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/default/data/ui/views/feedback.xml +0 -0
  155. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/default/use_case_library.conf +0 -0
  156. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/lookups/mitre_enrichment.csv +0 -0
  157. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/static/appIcon.png +0 -0
  158. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/static/appIconAlt.png +0 -0
  159. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/static/appIconAlt_2x.png +0 -0
  160. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/app_template/static/appIcon_2x.png +0 -0
  161. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/data_sources/sysmon_eventid_1.yml +0 -0
  162. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/datamodels_cim.conf +0 -0
  163. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/datamodels_custom.conf +0 -0
  164. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/deployments/escu_default_configuration_anomaly.yml +0 -0
  165. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/deployments/escu_default_configuration_baseline.yml +0 -0
  166. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/deployments/escu_default_configuration_correlation.yml +0 -0
  167. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/deployments/escu_default_configuration_hunting.yml +0 -0
  168. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/deployments/escu_default_configuration_ttp.yml +0 -0
  169. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/detections/application/.gitkeep +0 -0
  170. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/detections/cloud/.gitkeep +0 -0
  171. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/detections/endpoint/anomalous_usage_of_7zip.yml +0 -0
  172. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/detections/network/.gitkeep +0 -0
  173. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/detections/web/.gitkeep +0 -0
  174. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/macros/security_content_ctime.yml +0 -0
  175. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/macros/security_content_summariesonly.yml +0 -0
  176. {contentctl-4.4.3 → contentctl-4.4.4}/contentctl/templates/stories/cobalt_strike.yml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: contentctl
3
- Version: 4.4.3
3
+ Version: 4.4.4
4
4
  Summary: Splunk Content Control Tool
5
5
  License: Apache 2.0
6
6
  Author: STRT
@@ -51,7 +51,9 @@ class Build:
51
51
  updated_conf_files.update(conf_output.writeObjects(input_dto.director_output_dto.lookups, SecurityContentType.lookups))
52
52
  updated_conf_files.update(conf_output.writeObjects(input_dto.director_output_dto.macros, SecurityContentType.macros))
53
53
  updated_conf_files.update(conf_output.writeObjects(input_dto.director_output_dto.dashboards, SecurityContentType.dashboards))
54
- updated_conf_files.update(conf_output.writeAppConf())
54
+ updated_conf_files.update(conf_output.writeMiscellaneousAppFiles())
55
+
56
+
55
57
 
56
58
  #Ensure that the conf file we just generated/update is syntactically valid
57
59
  for conf_file in updated_conf_files:
@@ -0,0 +1,55 @@
1
+ from contentctl.objects.config import deploy_acs, StackType
2
+ from requests import post
3
+ import pprint
4
+
5
+
6
+ class Deploy:
7
+ def execute(self, config: deploy_acs, appinspect_token:str) -> None:
8
+
9
+ #The following common headers are used by both Clasic and Victoria
10
+ headers = {
11
+ 'Authorization': f'Bearer {config.splunk_cloud_jwt_token}',
12
+ 'ACS-Legal-Ack': 'Y'
13
+ }
14
+ try:
15
+
16
+ with open(config.getPackageFilePath(include_version=False),'rb') as app_data:
17
+ #request_data = app_data.read()
18
+ if config.stack_type == StackType.classic:
19
+ # Classic instead uses a form to store token and package
20
+ # https://docs.splunk.com/Documentation/SplunkCloud/9.1.2308/Config/ManageApps#Manage_private_apps_using_the_ACS_API_on_Classic_Experience
21
+ address = f"https://admin.splunk.com/{config.splunk_cloud_stack}/adminconfig/v2/apps"
22
+
23
+ form_data = {
24
+ 'token': (None, appinspect_token),
25
+ 'package': app_data
26
+ }
27
+ res = post(address, headers=headers, files = form_data)
28
+ elif config.stack_type == StackType.victoria:
29
+ # Victoria uses the X-Splunk-Authorization Header
30
+ # It also uses --data-binary for the app content
31
+ # https://docs.splunk.com/Documentation/SplunkCloud/9.1.2308/Config/ManageApps#Manage_private_apps_using_the_ACS_API_on_Victoria_Experience
32
+ headers.update({'X-Splunk-Authorization': appinspect_token})
33
+ address = f"https://admin.splunk.com/{config.splunk_cloud_stack}/adminconfig/v2/apps/victoria"
34
+ res = post(address, headers=headers, data=app_data.read())
35
+ else:
36
+ raise Exception(f"Unsupported stack type: '{config.stack_type}'")
37
+ except Exception as e:
38
+ raise Exception(f"Error installing to stack '{config.splunk_cloud_stack}' (stack_type='{config.stack_type}') via ACS:\n{str(e)}")
39
+
40
+ try:
41
+ # Request went through and completed, but may have returned a non-successful error code.
42
+ # This likely includes a more verbose response describing the error
43
+ res.raise_for_status()
44
+ print(res.json())
45
+ except Exception as e:
46
+ try:
47
+ error_text = res.json()
48
+ except Exception as e:
49
+ error_text = "No error text - request failed"
50
+ formatted_error_text = pprint.pformat(error_text)
51
+ print("While this may not be the cause of your error, ensure that the uid and appid of your Private App does not exist in Splunkbase\n"
52
+ "ACS cannot deploy and app with the same uid or appid as one that exists in Splunkbase.")
53
+ raise Exception(f"Error installing to stack '{config.splunk_cloud_stack}' (stack_type='{config.stack_type}') via ACS:\n{formatted_error_text}")
54
+
55
+ print(f"'{config.getPackageFilePath(include_version=False)}' successfully installed to stack '{config.splunk_cloud_stack}' (stack_type='{config.stack_type}') via ACS!")
@@ -19,6 +19,7 @@ from contentctl.actions.test import TestInputDto
19
19
  from contentctl.actions.reporting import ReportingInputDto, Reporting
20
20
  from contentctl.actions.inspect import Inspect
21
21
  from contentctl.input.yml_reader import YmlReader
22
+ from contentctl.actions.deploy_acs import Deploy
22
23
  from contentctl.actions.release_notes import ReleaseNotes
23
24
 
24
25
  # def print_ascii_art():
@@ -95,8 +96,11 @@ def new_func(config:new):
95
96
 
96
97
 
97
98
  def deploy_acs_func(config:deploy_acs):
98
- #This is a bit challenging to get to work with the default values.
99
- raise Exception("deploy acs not yet implemented")
99
+ print("Building and inspecting app...")
100
+ token = inspect_func(config)
101
+ print("App successfully built and inspected.")
102
+ print("Deploying app...")
103
+ Deploy().execute(config, token)
100
104
 
101
105
  def test_common_func(config:test_common):
102
106
  if type(config) == test:
@@ -294,6 +294,7 @@ class StackType(StrEnum):
294
294
 
295
295
 
296
296
  class inspect(build):
297
+
297
298
  splunk_api_username: str = Field(
298
299
  description="Splunk API username used for appinspect and Splunkbase downloads."
299
300
  )
@@ -57,19 +57,26 @@ class ConfOutput:
57
57
  pass
58
58
 
59
59
 
60
- def writeAppConf(self)->set[pathlib.Path]:
60
+
61
+
62
+ def writeMiscellaneousAppFiles(self)->set[pathlib.Path]:
61
63
  written_files:set[pathlib.Path] = set()
62
- for output_app_path, template_name in [ ("default/app.conf", "app.conf.j2"),
63
- ("default/content-version.conf", "content-version.j2")]:
64
- written_files.add(ConfWriter.writeConfFile(pathlib.Path(output_app_path),
65
- template_name,
66
- self.config,
67
- [self.config.app]))
64
+
65
+ written_files.add(ConfWriter.writeConfFile(pathlib.Path("default/content-version.conf"),
66
+ "content-version.j2",
67
+ self.config,
68
+ [self.config.app]))
68
69
 
69
70
  written_files.add(ConfWriter.writeManifestFile(pathlib.Path("app.manifest"),
70
71
  "app.manifest.j2",
71
72
  self.config,
72
73
  [self.config.app]))
74
+
75
+ written_files.add(ConfWriter.writeServerConf(self.config))
76
+
77
+ written_files.add(ConfWriter.writeAppConf(self.config))
78
+
79
+
73
80
  return written_files
74
81
 
75
82
 
@@ -12,6 +12,76 @@ from contentctl.objects.dashboard import Dashboard
12
12
  from contentctl.objects.config import build
13
13
  import xml.etree.ElementTree as ET
14
14
 
15
+ # This list is not exhaustive of all default conf files, but should be
16
+ # sufficient for our purposes.
17
+ DEFAULT_CONF_FILES = [
18
+ "alert_actions.conf",
19
+ "app.conf",
20
+ "audit.conf",
21
+ "authentication.conf",
22
+ "authorize.conf",
23
+ "bookmarks.conf",
24
+ "checklist.conf",
25
+ "collections.conf",
26
+ "commands.conf",
27
+ "conf.conf",
28
+ "datamodels.conf",
29
+ "datatypesbnf.conf",
30
+ "default-mode.conf",
31
+ "deploymentclient.conf",
32
+ "distsearch.conf",
33
+ "event_renderers.conf",
34
+ "eventdiscoverer.conf",
35
+ "eventtypes.conf",
36
+ "federated.conf",
37
+ "fields.conf",
38
+ "global-banner.conf",
39
+ "health.conf",
40
+ "indexes.conf",
41
+ "inputs.conf",
42
+ "limits.conf",
43
+ "literals.conf",
44
+ "livetail.conf",
45
+ "macros.conf",
46
+ "messages.conf",
47
+ "metric_alerts.conf",
48
+ "metric_rollups.conf",
49
+ "multikv.conf",
50
+ "outputs.conf",
51
+ "passwords.conf",
52
+ "procmon-filters.conf",
53
+ "props.conf",
54
+ "pubsub.conf",
55
+ "restmap.conf",
56
+ "rolling_upgrade.conf",
57
+ "savedsearches.conf",
58
+ "searchbnf.conf",
59
+ "segmenters.conf",
60
+ "server.conf",
61
+ "serverclass.conf",
62
+ "serverclass.seed.xml.conf",
63
+ "source-classifier.conf",
64
+ "sourcetypes.conf",
65
+ "tags.conf",
66
+ "telemetry.conf",
67
+ "times.conf",
68
+ "transactiontypes.conf",
69
+ "transforms.conf",
70
+ "ui-prefs.conf",
71
+ "ui-tour.conf",
72
+ "user-prefs.conf",
73
+ "user-seed.conf",
74
+ "viewstates.conf",
75
+ "visualizations.conf",
76
+ "web-features.conf",
77
+ "web.conf",
78
+ "wmi.conf",
79
+ "workflow_actions.conf",
80
+ "workload_policy.conf",
81
+ "workload_pools.conf",
82
+ "workload_rules.conf",
83
+ ]
84
+
15
85
  class ConfWriter():
16
86
 
17
87
  @staticmethod
@@ -57,6 +127,52 @@ class ConfWriter():
57
127
  ConfWriter.validateConfFile(output_path)
58
128
  return output_path
59
129
 
130
+ @staticmethod
131
+ def getCustomConfFileStems(config:build)->list[str]:
132
+ # Get all the conf files in the default directory. We must make a reload.conf_file = simple key/value for them if
133
+ # they are custom conf files
134
+ default_path = config.getPackageDirectoryPath()/"default"
135
+ conf_files = default_path.glob("*.conf")
136
+
137
+ custom_conf_file_stems = [conf_file.stem for conf_file in conf_files if conf_file.name not in DEFAULT_CONF_FILES]
138
+ return sorted(custom_conf_file_stems)
139
+
140
+ @staticmethod
141
+ def writeServerConf(config: build) -> pathlib.Path:
142
+ app_output_path = pathlib.Path("default/server.conf")
143
+ template_name = "server.conf.j2"
144
+
145
+ j2_env = ConfWriter.getJ2Environment()
146
+ template = j2_env.get_template(template_name)
147
+
148
+ output = template.render(custom_conf_files=ConfWriter.getCustomConfFileStems(config))
149
+
150
+ output_path = config.getPackageDirectoryPath()/app_output_path
151
+ output_path.parent.mkdir(parents=True, exist_ok=True)
152
+ with open(output_path, 'a') as f:
153
+ output = output.encode('utf-8', 'ignore').decode('utf-8')
154
+ f.write(output)
155
+ return output_path
156
+
157
+
158
+ @staticmethod
159
+ def writeAppConf(config: build) -> pathlib.Path:
160
+ app_output_path = pathlib.Path("default/app.conf")
161
+ template_name = "app.conf.j2"
162
+
163
+ j2_env = ConfWriter.getJ2Environment()
164
+ template = j2_env.get_template(template_name)
165
+
166
+ output = template.render(custom_conf_files=ConfWriter.getCustomConfFileStems(config),
167
+ app=config.app)
168
+
169
+ output_path = config.getPackageDirectoryPath()/app_output_path
170
+ output_path.parent.mkdir(parents=True, exist_ok=True)
171
+ with open(output_path, 'a') as f:
172
+ output = output.encode('utf-8', 'ignore').decode('utf-8')
173
+ f.write(output)
174
+ return output_path
175
+
60
176
  @staticmethod
61
177
  def writeManifestFile(app_output_path:pathlib.Path, template_name : str, config: build, objects : list) -> pathlib.Path:
62
178
  j2_env = ConfWriter.getJ2Environment()
@@ -70,6 +186,7 @@ class ConfWriter():
70
186
  output = output.encode('utf-8', 'ignore').decode('utf-8')
71
187
  f.write(output)
72
188
  return output_path
189
+
73
190
 
74
191
 
75
192
  @staticmethod
@@ -218,8 +335,3 @@ class ConfWriter():
218
335
  _ = json.load(manifestFile)
219
336
  except Exception as e:
220
337
  raise Exception(f"Failed to validate .manifest file {str(path)} (Note that .manifest files should contain only valid JSON-formatted data): {str(e)}")
221
-
222
-
223
-
224
-
225
-
@@ -0,0 +1,37 @@
1
+ ## Splunk app configuration file
2
+
3
+ [install]
4
+ is_configured = false
5
+ state = enabled
6
+ state_change_requires_restart = false
7
+ build = {{ app.build }}
8
+
9
+ [triggers]
10
+ {% for custom_conf_file in custom_conf_files%}
11
+ reload.{{custom_conf_file}} = simple
12
+ {% endfor %}
13
+
14
+ [launcher]
15
+ author = {{ app.author_company }}
16
+ version = {{ app.version }}
17
+ description = {{ app.description | escapeNewlines() }}
18
+
19
+ [ui]
20
+ is_visible = true
21
+ label = {{ app.title }}
22
+
23
+ [package]
24
+ id = {{ app.appid }}
25
+ {% if app.uid == 3449 %}
26
+ check_for_updates = true
27
+ {% else %}
28
+ check_for_updates = false
29
+ {% endif %}
30
+
31
+ [id]
32
+ version = {{ app.version }}
33
+ name = {{ app.appid }}
34
+
35
+
36
+
37
+
@@ -1,5 +1,6 @@
1
1
  {
2
- "schemaVersion": "1.0.0",
2
+ "schemaVersion": "1.0.0",
3
+ "targetWorkloads": ["_search_heads"],
3
4
  "info": {
4
5
  "title": "{{ objects[0].title }}",
5
6
  "id": {
@@ -0,0 +1,4 @@
1
+ [shclustering]
2
+ {% for custom_conf_file in custom_conf_files%}
3
+ conf_replication_include.{{custom_conf_file}} = true
4
+ {% endfor %}
@@ -1,6 +1,6 @@
1
1
  ## shared Application-level permissions
2
2
  []
3
- access = read : [ * ], write : [ admin ]
3
+ access = read : [ * ], write : [ admin, sc_admin ]
4
4
  export = system
5
5
 
6
6
  [savedsearches]
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "contentctl"
3
- version = "4.4.3"
3
+ version = "4.4.4"
4
4
 
5
5
  description = "Splunk Content Control Tool"
6
6
  authors = ["STRT <research@splunk.com>"]
@@ -1,38 +0,0 @@
1
- from dataclasses import dataclass
2
- from contentctl.input.director import DirectorInputDto
3
- from contentctl.output.conf_output import ConfOutput
4
-
5
-
6
- from typing import Union
7
-
8
- @dataclass(frozen=True)
9
- class ACSDeployInputDto:
10
- director_input_dto: DirectorInputDto
11
- splunk_api_username: str
12
- splunk_api_password: str
13
- splunk_cloud_jwt_token: str
14
- splunk_cloud_stack: str
15
- stack_type: str
16
-
17
-
18
- class Deploy:
19
- def execute(self, input_dto: ACSDeployInputDto) -> None:
20
-
21
- conf_output = ConfOutput(input_dto.director_input_dto.input_path, input_dto.director_input_dto.config)
22
-
23
- appinspect_token = conf_output.inspectAppAPI(input_dto.splunk_api_username, input_dto.splunk_api_password, input_dto.stack_type)
24
-
25
-
26
- if input_dto.splunk_cloud_jwt_token is None or input_dto.splunk_cloud_stack is None:
27
- if input_dto.splunk_cloud_jwt_token is None:
28
- raise Exception("Cannot deploy app via ACS, --splunk_cloud_jwt_token was not defined on command line.")
29
- else:
30
- raise Exception("Cannot deploy app via ACS, --splunk_cloud_stack was not defined on command line.")
31
-
32
- conf_output.deploy_via_acs(input_dto.splunk_cloud_jwt_token,
33
- input_dto.splunk_cloud_stack,
34
- appinspect_token,
35
- input_dto.stack_type)
36
-
37
-
38
-
@@ -1,35 +0,0 @@
1
- ## Splunk app configuration file
2
-
3
- [install]
4
- is_configured = false
5
- state = enabled
6
- state_change_requires_restart = false
7
- build = {{ objects[0].build }}
8
-
9
- [triggers]
10
- reload.analytic_stories = simple
11
- reload.usage_searches = simple
12
- reload.use_case_library = simple
13
- reload.correlationsearches = simple
14
- reload.analyticstories = simple
15
- reload.governance = simple
16
- reload.managed_configurations = simple
17
- reload.postprocess = simple
18
- reload.content-version = simple
19
- reload.es_investigations = simple
20
-
21
- [launcher]
22
- author = {{ objects[0].author_company }}
23
- version = {{ objects[0].version }}
24
- description = {{ objects[0].description | escapeNewlines() }}
25
-
26
- [ui]
27
- is_visible = true
28
- label = {{ objects[0].title }}
29
-
30
- [package]
31
- id = {{ objects[0].appid }}
32
-
33
-
34
-
35
-
@@ -1,30 +0,0 @@
1
- ## Splunk app configuration file
2
-
3
- [install]
4
- is_configured = false
5
- state = enabled
6
- state_change_requires_restart = false
7
- build = 16367
8
-
9
- [triggers]
10
- reload.analytic_stories = simple
11
- reload.use_case_library = simple
12
- reload.correlationsearches = simple
13
- reload.analyticstories = simple
14
- reload.governance = simple
15
- reload.managed_configurations = simple
16
- reload.postprocess = simple
17
- reload.content-version = simple
18
- reload.es_investigations = simple
19
-
20
- [launcher]
21
- author = Splunk
22
- version = 4.9.0
23
- description = Explore the Analytic Stories included with ES Content Updates.
24
-
25
- [ui]
26
- is_visible = true
27
- label = ES Content Updates
28
-
29
- [package]
30
- id = DA-ESS-ContentUpdate
@@ -1,2 +0,0 @@
1
- [content-version]
2
- version = 4.9.0
File without changes
File without changes
File without changes