mirror of
https://github.com/splunk/security_content
synced 2026-06-08 17:32:49 +00:00
Merge pull request #2374 from splunk/fix_app_renaming_in_init
Fix App Renaming in contentctl init/generate/build for custom apps
This commit is contained in:
@@ -106,6 +106,10 @@ class Initialize:
|
||||
#Information that will be used for generation of a custom manifest
|
||||
self.app_title = args.title
|
||||
self.app_name = args.name
|
||||
if not self.app_name.replace('-','').isalnum() and len(self.app_name.replace('-','')) > 0:
|
||||
# Basic check to see if the app_name is alphanumeric (no spaces or symbols) and, after any
|
||||
# - character(s) are removed it is still non-zero length
|
||||
raise(Exception(f"Error - app_name {self.app_name} is not valid. Name must be alphanumeric (no symbols or spaces). The only allowed special character is -."))
|
||||
self.app_version = args.version
|
||||
self.app_description = args.description
|
||||
self.app_author_name = args.author_name
|
||||
@@ -171,7 +175,25 @@ class Initialize:
|
||||
for fname in ["savedsearches_investigations.j2", "savedsearches_detections.j2", "analyticstories_investigations.j2", "analyticstories_detections.j2", "savedsearches_baselines.j2"]:
|
||||
full_path = os.path.join(filename_root, fname)
|
||||
self.simple_replace_line(full_path, original, updated)
|
||||
#Generate directories?
|
||||
|
||||
raw ='''.{app_name}'''
|
||||
original = raw.format(app_name="ESCU".lower()) #
|
||||
updated = raw.format(app_name=self.app_name.lower())
|
||||
filename_root = os.path.join(self.path,"bin/contentctl_project/contentctl_infrastructure/adapter/templates/")
|
||||
for fname in ["savedsearches_investigations.j2", "savedsearches_detections.j2", "savedsearches_baselines.j2"]:
|
||||
full_path = os.path.join(filename_root, fname)
|
||||
self.simple_replace_line(full_path, original, updated)
|
||||
|
||||
|
||||
raw ='''.{app_name}.'''
|
||||
original = raw.format(app_name="ESCU".lower()) #
|
||||
updated = raw.format(app_name=self.app_name.lower())
|
||||
filename_root = os.path.join(self.path,f"dist/{self.app_name}/default/data/ui/views/")
|
||||
for fname in ["escu_summary.xml"]:
|
||||
full_path = os.path.join(filename_root, fname)
|
||||
self.simple_replace_line(full_path, original, updated)
|
||||
|
||||
|
||||
|
||||
def generate_content_version_file(self):
|
||||
new_content_version = CONTENT_VERSION_FILE.format(version=self.app_version)
|
||||
|
||||
+32
-5
@@ -1,8 +1,11 @@
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import pathlib
|
||||
import os
|
||||
|
||||
from pydantic import ValidationError
|
||||
|
||||
from typing import Union
|
||||
from bin.contentctl_project.contentctl_core.application.builder.story_builder import StoryBuilder
|
||||
from bin.contentctl_project.contentctl_core.domain.entities.story import Story
|
||||
from bin.contentctl_project.contentctl_core.domain.entities.enums.enums import SecurityContentType
|
||||
@@ -13,9 +16,33 @@ class SecurityContentStoryBuilder(StoryBuilder):
|
||||
story: Story
|
||||
check_references: bool
|
||||
|
||||
def __init__(self, check_references: bool = False):
|
||||
def __init__(self, output_path:Union[str,None]=None, check_references: bool = False):
|
||||
self.check_references = check_references
|
||||
self.app_name = self.get_app_name_from_manifest(output_path)
|
||||
|
||||
def get_app_name_from_manifest(self, output_path:Union[str,None])->str:
|
||||
if output_path is None:
|
||||
return "ESCU"
|
||||
|
||||
try:
|
||||
manifest_path = pathlib.Path(os.path.join(output_path, "app.manifest"))
|
||||
except Exception as e:
|
||||
raise(Exception(f"Failed to convert string {output_path} to path: {str(e)}"))
|
||||
try:
|
||||
with open(manifest_path, "r") as manifestFile:
|
||||
manifest_obj = json.load(manifestFile)
|
||||
except Exception as e:
|
||||
raise(Exception(f"Failed to open manifest at path {manifest_path}: {str(e)}"))
|
||||
|
||||
try:
|
||||
app_name_from_manifest = manifest_obj['info']['id']['name']
|
||||
#Minor fix to shorten the name of ESCU detections and match with everything else
|
||||
if app_name_from_manifest == "DA-ESS-ContentUpdate":
|
||||
app_name_from_manifest = "ESCU"
|
||||
return app_name_from_manifest
|
||||
except Exception as e:
|
||||
raise(Exception(f"Manifest file {manifest_path} missing nested object ['info']['id']['name']: {str(e)}"))
|
||||
|
||||
def setObject(self, path: str) -> None:
|
||||
yml_dict = YmlReader.load_file(path)
|
||||
yml_dict["tags"]["name"] = yml_dict["name"]
|
||||
@@ -46,7 +73,7 @@ class SecurityContentStoryBuilder(StoryBuilder):
|
||||
if detection:
|
||||
for detection_analytic_story in detection.tags.analytic_story:
|
||||
if detection_analytic_story == self.story.name:
|
||||
matched_detection_names.append(str('ESCU - ' + detection.name + ' - Rule'))
|
||||
matched_detection_names.append(str(f'{self.app_name} - ' + detection.name + ' - Rule'))
|
||||
# SSE-638: detections object should at least contain the name attribute.
|
||||
# We also need a minimal set of the following attributes to satisfy docgen (doc_stories.j2):
|
||||
# name, source, type, tags.mitre_attack_enrichments.mitre_attack_technique
|
||||
@@ -84,7 +111,7 @@ class SecurityContentStoryBuilder(StoryBuilder):
|
||||
for baseline in baselines:
|
||||
for baseline_analytic_story in baseline.tags.analytic_story:
|
||||
if baseline_analytic_story == self.story.name:
|
||||
matched_baseline_names.append(str('ESCU - ' + baseline.name))
|
||||
matched_baseline_names.append(str(f'{self.app_name} - ' + baseline.name))
|
||||
|
||||
self.story.baseline_names = matched_baseline_names
|
||||
|
||||
@@ -94,7 +121,7 @@ class SecurityContentStoryBuilder(StoryBuilder):
|
||||
for investigation in investigations:
|
||||
for investigation_analytic_story in investigation.tags.analytic_story:
|
||||
if investigation_analytic_story == self.story.name:
|
||||
matched_investigation_names.append(str('ESCU - ' + investigation.name + ' - Response Task'))
|
||||
matched_investigation_names.append(str(f'{self.app_name} - ' + investigation.name + ' - Response Task'))
|
||||
matched_investigations.append(investigation)
|
||||
|
||||
self.story.investigation_names = matched_investigation_names
|
||||
|
||||
+2
-1
@@ -110,11 +110,12 @@ def generate(args) -> None:
|
||||
factory_input_dto = None
|
||||
ba_factory_input_dto = None
|
||||
if args.product in ["ESCU", "API"]:
|
||||
|
||||
factory_input_dto = FactoryInputDto(
|
||||
os.path.abspath(args.path),
|
||||
SecurityContentBasicBuilder(),
|
||||
SecurityContentDetectionBuilder(force_cached_or_offline=args.cached_and_offline, skip_enrichment=args.skip_enrichment),
|
||||
SecurityContentStoryBuilder(),
|
||||
SecurityContentStoryBuilder(output_path=args.output),
|
||||
SecurityContentBaselineBuilder(),
|
||||
SecurityContentInvestigationBuilder(),
|
||||
SecurityContentPlaybookBuilder(input_path=args.path),
|
||||
|
||||
Reference in New Issue
Block a user