From a71ae134225383b85557947c3fb673b9089f115a Mon Sep 17 00:00:00 2001 From: Dmytro <47281757+tarnopolskyi@users.noreply.github.com> Date: Mon, 17 Jun 2024 13:17:43 +0200 Subject: [PATCH 1/3] added-case-insensitive --- uncoder-core/app/translator/platforms/sigma/mapping.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uncoder-core/app/translator/platforms/sigma/mapping.py b/uncoder-core/app/translator/platforms/sigma/mapping.py index 3f23700d..1af791ac 100644 --- a/uncoder-core/app/translator/platforms/sigma/mapping.py +++ b/uncoder-core/app/translator/platforms/sigma/mapping.py @@ -19,9 +19,9 @@ def __init__( def is_suitable( self, service: Optional[list[str]], product: Optional[list[str]], category: Optional[list[str]] ) -> bool: - product_match = set(product or []).issubset(self.products) if product else False - category_match = set(category or []).issubset(self.categories) if category else False - service_match = set(service or []).issubset(self.services) if service else False + product_match = set(product_.lower() for product_ in product or []).issubset(self.products) if product else False + category_match = set(category_.lower() for category_ in category or []).issubset(self.categories) if category else False + service_match = set(service_.lower() for service_ in service or [] or []).issubset(self.services) if service else False if not product and not service: return category_match return product_match and service_match or product_match and category_match From 6c4dd6c32d8edb337fca7ea95e003deb7de934a0 Mon Sep 17 00:00:00 2001 From: Dmytro <47281757+tarnopolskyi@users.noreply.github.com> Date: Mon, 17 Jun 2024 13:17:48 +0200 Subject: [PATCH 2/3] run linter --- uncoder-core/app/translator/core/render.py | 14 +++++++++++--- .../palo_alto/renders/cortex_xsiam.py | 18 +++++++++--------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/uncoder-core/app/translator/core/render.py b/uncoder-core/app/translator/core/render.py index d7d0716a..b717826b 100644 --- a/uncoder-core/app/translator/core/render.py +++ b/uncoder-core/app/translator/core/render.py @@ -18,7 +18,7 @@ """ from abc import ABC, abstractmethod from collections.abc import Callable -from typing import Optional, Union +from typing import ClassVar, Optional, Union from app.translator.const import DEFAULT_VALUE_TYPE from app.translator.core.context_vars import return_only_first_query_ctx_var @@ -165,7 +165,14 @@ class QueryRender(ABC): is_single_line_comment: bool = False unsupported_functions_text = "Unsupported functions were excluded from the result query:" - platform_functions: PlatformFunctions = PlatformFunctions() + platform_functions: PlatformFunctions = None + + def __init__(self): + self.init_platform_functions() + + def init_platform_functions(self) -> None: + self.platform_functions = PlatformFunctions() + self.platform_functions.platform_query_render = self def render_not_supported_functions(self, not_supported_functions: list) -> str: line_template = f"{self.comment_symbol} " if self.comment_symbol and self.is_single_line_comment else "" @@ -193,9 +200,10 @@ class PlatformQueryRender(QueryRender): field_value_map = BaseQueryFieldValue(or_token=or_token) query_pattern = "{table} {query} {functions}" - raw_log_field_pattern_map: dict = None + raw_log_field_pattern_map: ClassVar[dict[str, str]] = None def __init__(self): + super().__init__() self.operator_map = { LogicalOperatorType.AND: f" {self.and_token} ", LogicalOperatorType.OR: f" {self.or_token} ", diff --git a/uncoder-core/app/translator/platforms/palo_alto/renders/cortex_xsiam.py b/uncoder-core/app/translator/platforms/palo_alto/renders/cortex_xsiam.py index 0af8206a..c0b032e4 100644 --- a/uncoder-core/app/translator/platforms/palo_alto/renders/cortex_xsiam.py +++ b/uncoder-core/app/translator/platforms/palo_alto/renders/cortex_xsiam.py @@ -16,7 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ -from typing import Optional, Union +from typing import ClassVar, Optional, Union from app.translator.const import DEFAULT_VALUE_TYPE from app.translator.core.custom_types.values import ValueType @@ -136,12 +136,12 @@ class CortexXQLQueryRender(PlatformQueryRender): details: PlatformDetails = cortex_xql_query_details mappings: CortexXQLMappings = cortex_xql_mappings is_strict_mapping = True - raw_log_field_pattern_map = { - 'regex': '| alter {field} = regextract(to_json_string(action_evtlog_data_fields)->{field}{{}}, "\\"(.*)\\"")', - 'object': '| alter {field_name} = json_extract_scalar({field_object} , "$.{field_path}")', - 'list': '| alter {field_name} = arraystring(json_extract_array({field_object} , "$.{field_path}")," ")' + raw_log_field_pattern_map: ClassVar[dict[str, str]] = { + "regex": '| alter {field} = regextract(to_json_string(action_evtlog_data_fields)->{field}{{}}, "\\"(.*)\\"")', + "object": '| alter {field_name} = json_extract_scalar({field_object} , "$.{field_path}")', + "list": '| alter {field_name} = arraystring(json_extract_array({field_object} , "$.{field_path}")," ")', } - platform_functions: CortexXQLFunctions = cortex_xql_functions + platform_functions: CortexXQLFunctions = None or_token = "or" and_token = "and" @@ -152,9 +152,9 @@ class CortexXQLQueryRender(PlatformQueryRender): comment_symbol = "//" is_single_line_comment = False - def __init__(self): - super().__init__() - self.platform_functions.manager.post_init_configure(self) + def init_platform_functions(self) -> None: + self.platform_functions = cortex_xql_functions + self.platform_functions.platform_query_render = self def process_raw_log_field(self, field: str, field_type: str) -> Optional[str]: raw_log_field_pattern = self.raw_log_field_pattern_map.get(field_type) From 9a9f093717f0678acfda0b9ed1dde0267deee560 Mon Sep 17 00:00:00 2001 From: Dmytro <47281757+tarnopolskyi@users.noreply.github.com> Date: Wed, 26 Jun 2024 10:16:49 +0200 Subject: [PATCH 3/3] Merge branch 'prod' into 'gis-case-insensitive-sigma-mapping' # Conflicts: # app/translator/platforms/palo_alto/renders/cortex_xsiam.py --- .../app/translator/core/context_vars.py | 2 +- .../app/translator/core/custom_types/time.py | 23 +++++++++ .../app/translator/core/exceptions/core.py | 18 ++++++- uncoder-core/app/translator/core/mapping.py | 4 ++ uncoder-core/app/translator/core/parser.py | 1 + uncoder-core/app/translator/core/render.py | 48 ++++++++++++------- .../app/translator/core/render_cti.py | 1 - .../app/translator/core/str_value_manager.py | 1 + .../palo_alto_cortex/aws_cloudtrail.yml | 3 +- .../palo_alto_cortex/azure_signinlogs.yml | 46 ++++++++++++++++++ .../platforms/palo_alto_cortex/default.yml | 3 +- .../platforms/palo_alto_cortex/dns.yml | 4 +- .../platforms/palo_alto_cortex/webserver.yml | 3 ++ .../palo_alto_cortex/windows_powershell.yml | 3 +- .../palo_alto_cortex/windows_security.yml | 6 ++- .../palo_alto_cortex/windows_sysmon.yml | 3 +- .../palo_alto_cortex/windows_system.yml | 4 +- .../mappings/platforms/qradar/default.yml | 11 ++++- .../platforms/qradar/windows_security.yml | 6 ++- .../platforms/sigma/azure_azureactivity.yml | 2 +- .../platforms/sigma/azure_azuread.yml | 2 +- .../mappings/platforms/sigma/azure_m365.yml | 2 +- .../platforms/athena/renders/athena.py | 6 ++- .../platforms/base/aql/renders/aql.py | 6 ++- .../platforms/base/aql/str_value_manager.py | 1 + .../platforms/base/aql/tokenizer.py | 1 + .../platforms/base/lucene/renders/lucene.py | 3 +- .../base/lucene/str_value_manager.py | 1 + .../platforms/base/lucene/tokenizer.py | 1 + .../platforms/base/spl/renders/spl.py | 2 +- .../platforms/base/sql/renders/sql.py | 6 ++- .../platforms/chronicle/parsers/chronicle.py | 1 - .../platforms/chronicle/renders/chronicle.py | 2 +- .../crowdstrike/parsers/crowdstrike.py | 1 + .../crowdstrike/renders/crowdstrike.py | 10 ++-- .../elasticsearch/parsers/detection_rule.py | 1 - .../elasticsearch/renders/detection_rule.py | 5 +- .../elasticsearch/renders/elast_alert.py | 2 +- .../platforms/elasticsearch/renders/kibana.py | 1 + .../elasticsearch/renders/xpack_watcher.py | 1 + .../forti_siem/renders/forti_siem_rule.py | 8 ++-- .../platforms/forti_siem/str_value_manager.py | 3 ++ .../platforms/hunters/renders/hunters.py | 6 ++- .../renders/logrhythm_axon_query.py | 9 +++- .../renders/logrhythm_axon_rule.py | 1 + .../platforms/logscale/parsers/logscale.py | 1 - .../logscale/parsers/logscale_alert.py | 1 - .../platforms/logscale/renders/logscale.py | 15 +++--- .../logscale/renders/logscale_alert.py | 1 + .../microsoft/parsers/microsoft_sentinel.py | 1 - .../parsers/microsoft_sentinel_rule.py | 1 - .../renders/microsoft_defender_cti.py | 1 + .../microsoft/renders/microsoft_sentinel.py | 14 ++++-- .../renders/microsoft_sentinel_rule.py | 1 + .../opensearch/renders/opensearch.py | 1 + .../opensearch/renders/opensearch_rule.py | 2 +- .../palo_alto/renders/cortex_xsiam.py | 7 ++- .../platforms/palo_alto/str_value_manager.py | 1 + .../platforms/qradar/renders/qradar.py | 1 + .../platforms/sigma/escape_manager.py | 2 +- .../platforms/sigma/models/compiler.py | 1 + .../platforms/sigma/models/modifiers.py | 5 +- .../platforms/sigma/parsers/sigma.py | 30 ++++++------ .../platforms/sigma/renders/sigma.py | 2 +- .../platforms/sigma/str_value_manager.py | 3 +- .../translator/platforms/sigma/tokenizer.py | 7 ++- .../platforms/splunk/renders/splunk.py | 9 ++-- .../platforms/splunk/renders/splunk_alert.py | 1 + 68 files changed, 278 insertions(+), 104 deletions(-) create mode 100644 uncoder-core/app/translator/core/custom_types/time.py create mode 100644 uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/azure_signinlogs.yml diff --git a/uncoder-core/app/translator/core/context_vars.py b/uncoder-core/app/translator/core/context_vars.py index 2fd36c45..591883d8 100644 --- a/uncoder-core/app/translator/core/context_vars.py +++ b/uncoder-core/app/translator/core/context_vars.py @@ -1,4 +1,4 @@ from contextvars import ContextVar return_only_first_query_ctx_var: ContextVar[bool] = ContextVar("return_only_first_query_ctx_var", default=False) -"""Set to True to return ony first query if rendered multiple options""" +"""Set to True to return only first query if rendered multiple options""" diff --git a/uncoder-core/app/translator/core/custom_types/time.py b/uncoder-core/app/translator/core/custom_types/time.py new file mode 100644 index 00000000..4cdc71fe --- /dev/null +++ b/uncoder-core/app/translator/core/custom_types/time.py @@ -0,0 +1,23 @@ +from app.translator.tools.custom_enum import CustomEnum + + +class TimeFrameType(CustomEnum): + years = "years" + months = "months" + days = "days" + hours = "hours" + minutes = "minutes" + + +class TimePartType(CustomEnum): + day = "day" + day_of_week = "day_of_week" + day_of_year = "day_of_year" + hour = "hour" + microsecond = "microsecond" + millisecond = "millisecond" + minute = "minute" + month = "month" + quarter = "quarter" + second = "second" + year = "year" diff --git a/uncoder-core/app/translator/core/exceptions/core.py b/uncoder-core/app/translator/core/exceptions/core.py index 68c66962..47810576 100644 --- a/uncoder-core/app/translator/core/exceptions/core.py +++ b/uncoder-core/app/translator/core/exceptions/core.py @@ -1,3 +1,6 @@ +from typing import Optional + + class NotImplementedException(BaseException): ... @@ -7,8 +10,19 @@ class BasePlatformException(BaseException): class StrictPlatformException(BasePlatformException): - def __init__(self, platform_name: str, field_name: str): - message = f"Platform {platform_name} has strict mapping. Source field {field_name} has no mapping." + field_name: str = None + + def __init__( + self, platform_name: str, field_name: str, mapping: Optional[str] = None, detected_fields: Optional[list] = None + ): + message = ( + f"Platform {platform_name} has strict mapping. " + f"Source fields: {', '.join(detected_fields) if detected_fields else field_name} has no mapping." + f" Mapping file: {mapping}." + if mapping + else "" + ) + self.field_name = field_name super().__init__(message) diff --git a/uncoder-core/app/translator/core/mapping.py b/uncoder-core/app/translator/core/mapping.py index 97726ae9..bdab5f6d 100644 --- a/uncoder-core/app/translator/core/mapping.py +++ b/uncoder-core/app/translator/core/mapping.py @@ -20,6 +20,10 @@ def is_suitable(self, *args, **kwargs) -> bool: def __str__(self) -> str: raise NotImplementedError("Abstract method") + @property + def default_source(self) -> dict: + return self._default_source + class FieldMapping: def __init__(self, generic_field_name: str, platform_field_name: str): diff --git a/uncoder-core/app/translator/core/parser.py b/uncoder-core/app/translator/core/parser.py index 791734be..7cc10ec1 100644 --- a/uncoder-core/app/translator/core/parser.py +++ b/uncoder-core/app/translator/core/parser.py @@ -15,6 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ----------------------------------------------------------------- """ + import re from abc import ABC, abstractmethod from typing import Union diff --git a/uncoder-core/app/translator/core/render.py b/uncoder-core/app/translator/core/render.py index b717826b..b326cf96 100644 --- a/uncoder-core/app/translator/core/render.py +++ b/uncoder-core/app/translator/core/render.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from abc import ABC, abstractmethod from collections.abc import Callable from typing import ClassVar, Optional, Union @@ -196,10 +197,10 @@ class PlatformQueryRender(QueryRender): not_token = "not" group_token = "(%s)" + query_parts_delimiter = " " field_value_map = BaseQueryFieldValue(or_token=or_token) - query_pattern = "{table} {query} {functions}" raw_log_field_pattern_map: ClassVar[dict[str, str]] = None def __init__(self): @@ -210,9 +211,9 @@ def __init__(self): LogicalOperatorType.NOT: f" {self.not_token} ", } - def generate_prefix(self, log_source_signature: LogSourceSignature, functions_prefix: str = "") -> str: # noqa: ARG002 - if str(log_source_signature): - return f"{log_source_signature!s} {self.and_token}" + def generate_prefix(self, log_source_signature: Optional[LogSourceSignature], functions_prefix: str = "") -> str: # noqa: ARG002 + if log_source_signature and str(log_source_signature): + return f"{log_source_signature} {self.and_token}" return "" def generate_functions(self, functions: list[Function], source_mapping: SourceMapping) -> RenderedFunctions: @@ -262,8 +263,14 @@ def apply_token(self, token: Union[FieldValue, Keyword, Identifier], source_mapp def generate_query(self, tokens: list[TOKEN_TYPE], source_mapping: SourceMapping) -> str: result_values = [] + unmapped_fields = set() for token in tokens: - result_values.append(self.apply_token(token=token, source_mapping=source_mapping)) + try: + result_values.append(self.apply_token(token=token, source_mapping=source_mapping)) + except StrictPlatformException as err: + unmapped_fields.add(err.field_name) + if unmapped_fields: + raise StrictPlatformException(self.details.name, "", source_mapping.source_id, sorted(unmapped_fields)) return "".join(result_values) def wrap_query_with_meta_info(self, meta_info: MetaInfoContainer, query: str) -> str: @@ -280,6 +287,14 @@ def wrap_query_with_meta_info(self, meta_info: MetaInfoContainer, query: str) -> query = f"{query}\n\n{query_meta_info}" return query + @staticmethod + def _finalize_search_query(query: str) -> str: + return query + + def _join_query_parts(self, prefix: str, query: str, functions: str) -> str: + parts = filter(lambda s: bool(s), map(str.strip, [prefix, self._finalize_search_query(query), functions])) + return self.query_parts_delimiter.join(parts) + def finalize_query( self, prefix: str, @@ -291,8 +306,7 @@ def finalize_query( *args, # noqa: ARG002 **kwargs, # noqa: ARG002 ) -> str: - query = self.query_pattern.format(prefix=prefix, query=query, functions=functions).strip() - + query = self._join_query_parts(prefix, query, functions) query = self.wrap_query_with_meta_info(meta_info=meta_info, query=query) if not_supported_functions: rendered_not_supported = self.render_not_supported_functions(not_supported_functions) @@ -335,15 +349,15 @@ def _generate_from_raw_query_container(self, query_container: RawQueryContainer) def process_raw_log_field(self, field: str, field_type: str) -> Optional[str]: if raw_log_field_pattern := self.raw_log_field_pattern_map.get(field_type): - return raw_log_field_pattern.pattern.format(field=field) + return raw_log_field_pattern.format(field=field) def process_raw_log_field_prefix(self, field: str, source_mapping: SourceMapping) -> Optional[list]: if isinstance(field, list): - list_of_prefix = [] + prefix_list = [] for f in field: - if prepared_prefix := self.process_raw_log_field_prefix(field=f, source_mapping=source_mapping): - list_of_prefix.extend(prepared_prefix) - return list_of_prefix + if _prefix_list := self.process_raw_log_field_prefix(field=f, source_mapping=source_mapping): + prefix_list.extend(_prefix_list) + return prefix_list if raw_log_field_type := source_mapping.raw_log_fields.get(field): return [self.process_raw_log_field(field=field, field_type=raw_log_field_type)] @@ -360,9 +374,11 @@ def generate_raw_log_fields(self, fields: list[Field], source_mapping: SourceMap ) if not mapped_field and self.is_strict_mapping: raise StrictPlatformException(field_name=field.source_name, platform_name=self.details.name) - if field_prefix := self.process_raw_log_field_prefix(field=mapped_field, source_mapping=source_mapping): - defined_raw_log_fields.extend(field_prefix) - return "\n".join(set(defined_raw_log_fields)) + if prefix_list := self.process_raw_log_field_prefix(field=mapped_field, source_mapping=source_mapping): + for prefix in prefix_list: + if prefix not in defined_raw_log_fields: + defined_raw_log_fields.append(prefix) + return "\n".join(defined_raw_log_fields) def _generate_from_tokenized_query_container(self, query_container: TokenizedQueryContainer) -> str: queries_map = {} @@ -377,7 +393,7 @@ def _generate_from_tokenized_query_container(self, query_container: TokenizedQue defined_raw_log_fields = self.generate_raw_log_fields( fields=query_container.meta_info.query_fields, source_mapping=source_mapping ) - prefix += f"\n{defined_raw_log_fields}\n" + prefix += f"\n{defined_raw_log_fields}" result = self.generate_query(tokens=query_container.tokens, source_mapping=source_mapping) except StrictPlatformException as err: errors.append(err) diff --git a/uncoder-core/app/translator/core/render_cti.py b/uncoder-core/app/translator/core/render_cti.py index 52a65ea6..20bfb7bf 100644 --- a/uncoder-core/app/translator/core/render_cti.py +++ b/uncoder-core/app/translator/core/render_cti.py @@ -17,7 +17,6 @@ ----------------------------------------------------------------- """ - from app.translator.core.models.iocs import IocsChunkValue from app.translator.core.models.platform_details import PlatformDetails diff --git a/uncoder-core/app/translator/core/str_value_manager.py b/uncoder-core/app/translator/core/str_value_manager.py index cd7523c0..74a9f532 100644 --- a/uncoder-core/app/translator/core/str_value_manager.py +++ b/uncoder-core/app/translator/core/str_value_manager.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import ClassVar, Optional, TypeVar, Union from app.translator.core.custom_types.values import ValueType diff --git a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/aws_cloudtrail.yml b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/aws_cloudtrail.yml index f8327a54..980f2125 100644 --- a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/aws_cloudtrail.yml +++ b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/aws_cloudtrail.yml @@ -32,4 +32,5 @@ raw_log_fields: userIdentity.principalId: object userIdentity.sessionContext.sessionIssuer.type: object userIdentity.type: object - userIdentity.userName: object \ No newline at end of file + userIdentity.userName: object + requestParameters.publiclyAccessible: object \ No newline at end of file diff --git a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/azure_signinlogs.yml b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/azure_signinlogs.yml new file mode 100644 index 00000000..b5b84cde --- /dev/null +++ b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/azure_signinlogs.yml @@ -0,0 +1,46 @@ +platform: Palo Alto XSIAM +source: azure_signinlogs + + +default_log_source: + dataset: msft_azure_raw + +field_mapping: + AppDisplayName: properties.appDisplayName + AppId: properties.appId + AuthenticationRequirement: properties.authenticationRequirement + Category: properties.category + ConditionalAccessStatus: properties.conditionalAccessStatus + DeviceDetail: properties.deviceDetail + IsInteractive: properties.isInteractive + NetworkLocationDetails: properties.networkLocationDetails + ResourceDisplayName: properties.resourceDisplayName + ResourceIdentity: properties.resourceIdentity + ResultDescription: properties.resultDescription + ResultType: properties.resultType + Status.errorCode: properties.status.errorCode + Status: properties.status + Status.failureReason: properties.status.failureReason + TokenIssuerType: properties.tokenIssuerType + UserAgent: properties.userAgent + UserPrincipalName: properties.userPrincipalName + +raw_log_fields: + properties.appDisplayName: object + properties.appId: object + properties.authenticationRequirement: object + properties.category: object + properties.conditionalAccessStatus: object + properties.deviceDetail: object + properties.isInteractive: object + properties.networkLocationDetails: object + properties.resourceDisplayName: object + properties.resourceIdentity: object + properties.resultDescription: object + properties.resultType: object + properties.status.errorCode: object + properties.status: object + properties.status.failureReason: object + properties.tokenIssuerType: object + properties.userAgent: object + properties.userPrincipalName: object \ No newline at end of file diff --git a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/default.yml b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/default.yml index 81d9dcc8..fa904aaf 100644 --- a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/default.yml +++ b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/default.yml @@ -77,6 +77,7 @@ field_mapping: OldTargetUserName: xdm.target.user.username UserPrincipalName: xdm.source.user.username DestAddress: xdm.target.ipv4 + SubjectAccountName: xdm.source.user.username SubjectUserName: xdm.source.user.username SubjectUserSid: xdm.source.user.identifier SourceAddr: xdm.source.ipv4 @@ -117,7 +118,6 @@ field_mapping: method: xdm.network.http.method notice.user_agent: xdm.network.http.browser hasIdentity: xdm.source.user.identity_type - SubjectAccountName: xdm.source.user.username ComputerName: xdm.source.host.hostname ExternalSeverity: xdm.alert.severity SourceMAC: xdm.source.host.mac_addresses @@ -125,3 +125,4 @@ field_mapping: SourceOS: xdm.source.host.os DestinationOS: xdm.target.host.os url_category: xdm.network.http.url_category + EventSeverity: xdm.alert.severity diff --git a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/dns.yml b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/dns.yml index 65cbbbad..e489fd50 100644 --- a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/dns.yml +++ b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/dns.yml @@ -8,4 +8,6 @@ field_mapping: dns-query: xdm.network.dns.dns_question.name dns-answer: xdm.network.dns.dns_resource_record.value #dns-record: dns-record - dns_query_name: xdm.network.dns.dns_question.name \ No newline at end of file + dns_query_name: xdm.network.dns.dns_question.name + QueryName: xdm.network.dns.dns_question.name + query: xdm.network.dns.dns_question.name \ No newline at end of file diff --git a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/webserver.yml b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/webserver.yml index 505d2498..7a1eaa84 100644 --- a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/webserver.yml +++ b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/webserver.yml @@ -14,3 +14,6 @@ field_mapping: sc-status: xdm.network.http.response_code cs-uri-stem: xdm.network.http.url cs-uri-query: xdm.network.http.url + c-uri-path: xdm.network.http.url + uri_path: xdm.network.http.url + cs-uri: xdm.network.http.url diff --git a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_powershell.yml b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_powershell.yml index 1d2e0ef4..41ed1439 100644 --- a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_powershell.yml +++ b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_powershell.yml @@ -16,4 +16,5 @@ raw_log_fields: HostApplication: regex ContextInfo: regex HostName: regex - EngineVersion: regex \ No newline at end of file + EngineVersion: regex + Path: regex \ No newline at end of file diff --git a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_security.yml b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_security.yml index a1a1e613..59a56f71 100644 --- a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_security.yml +++ b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_security.yml @@ -7,7 +7,8 @@ default_log_source: field_mapping: EventID: action_evtlog_event_id Provider_Name: provider_name - + SubjectAccountName: actor_effective_username + raw_log_fields: ParentImage: regex AccessMask: regex @@ -147,4 +148,5 @@ raw_log_fields: ExceptionCode: regex Service: regex SamAccountName: regex - ImpersonationLevel: regex \ No newline at end of file + ImpersonationLevel: regex + PrimaryGroupId: regex \ No newline at end of file diff --git a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_sysmon.yml b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_sysmon.yml index bc88c7c6..a15909c9 100644 --- a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_sysmon.yml +++ b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_sysmon.yml @@ -57,4 +57,5 @@ raw_log_fields: FileVersion: regex StartAddress: regex StartFunction: regex - EventType: regex \ No newline at end of file + EventType: regex + GrantedAccess: regex \ No newline at end of file diff --git a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_system.yml b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_system.yml index 889872e6..07730124 100644 --- a/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_system.yml +++ b/uncoder-core/app/translator/mappings/platforms/palo_alto_cortex/windows_system.yml @@ -20,4 +20,6 @@ raw_log_fields: param1: regex param2: regex Channel: regex - DeviceName: regex \ No newline at end of file + DeviceName: regex + Message: regex + ComputerName: regex \ No newline at end of file diff --git a/uncoder-core/app/translator/mappings/platforms/qradar/default.yml b/uncoder-core/app/translator/mappings/platforms/qradar/default.yml index df7d8daa..23e8b1bd 100644 --- a/uncoder-core/app/translator/mappings/platforms/qradar/default.yml +++ b/uncoder-core/app/translator/mappings/platforms/qradar/default.yml @@ -13,9 +13,12 @@ field_mapping: dst-port: - DstPort - DestinationPort + - remoteport dst-hostname: DstHost src-hostname: SrcHost - src-port: SourcePort + src-port: + - SourcePort + - localport src-ip: - sourceip - source_ip @@ -27,6 +30,7 @@ field_mapping: - destination_ip - destinationIP - destinationaddress + - destination User: - userName - EventUserName @@ -39,10 +43,12 @@ field_mapping: - HostCount-source - identityHostName - sourceAssetName + - HostCount-src DestinationHostname: - HostCount-destination - Recipient Host - DestinationHostName + - HostCount-dst src-packets: - PacketRatio-src - src-packets @@ -62,4 +68,5 @@ field_mapping: DestinationOS: DestinationOS TargetUserName: DestinationUserName SourceUserName: SourceUserName - url_category: XForceCategoryByURL \ No newline at end of file + url_category: XForceCategoryByURL + EventSeverity: EventSeverity \ No newline at end of file diff --git a/uncoder-core/app/translator/mappings/platforms/qradar/windows_security.yml b/uncoder-core/app/translator/mappings/platforms/qradar/windows_security.yml index 20883e94..7d01b97e 100644 --- a/uncoder-core/app/translator/mappings/platforms/qradar/windows_security.yml +++ b/uncoder-core/app/translator/mappings/platforms/qradar/windows_security.yml @@ -130,6 +130,9 @@ field_mapping: NewValue: NewValue Source: Source Status: Status + SubjectAccountName: + - Subject Account Name + - SubjectAccountName SubjectDomainName: SubjectDomainName SubjectUserName: Target Username SubjectUserSid: SubjectUserSid @@ -171,5 +174,4 @@ field_mapping: UserID: UserID ParentProcessName: Parent Process Name Service: Service - hasIdentity: hasIdentity - SubjectAccountName: SubjectAccountName \ No newline at end of file + hasIdentity: hasIdentity \ No newline at end of file diff --git a/uncoder-core/app/translator/mappings/platforms/sigma/azure_azureactivity.yml b/uncoder-core/app/translator/mappings/platforms/sigma/azure_azureactivity.yml index c8d090a5..7a17a916 100644 --- a/uncoder-core/app/translator/mappings/platforms/sigma/azure_azureactivity.yml +++ b/uncoder-core/app/translator/mappings/platforms/sigma/azure_azureactivity.yml @@ -4,7 +4,7 @@ source: azure_azureactivity log_source: product: [azure] - service: [azureactivity] + service: [azureactivity, activitylogs] default_log_source: product: azure diff --git a/uncoder-core/app/translator/mappings/platforms/sigma/azure_azuread.yml b/uncoder-core/app/translator/mappings/platforms/sigma/azure_azuread.yml index 54594bb0..d46b9688 100644 --- a/uncoder-core/app/translator/mappings/platforms/sigma/azure_azuread.yml +++ b/uncoder-core/app/translator/mappings/platforms/sigma/azure_azuread.yml @@ -4,7 +4,7 @@ source: azure_azuread log_source: product: [azure] - service: [azuread] + service: [azuread, auditlogs] default_log_source: product: azure diff --git a/uncoder-core/app/translator/mappings/platforms/sigma/azure_m365.yml b/uncoder-core/app/translator/mappings/platforms/sigma/azure_m365.yml index 7d2d1c46..b9877a5b 100644 --- a/uncoder-core/app/translator/mappings/platforms/sigma/azure_m365.yml +++ b/uncoder-core/app/translator/mappings/platforms/sigma/azure_m365.yml @@ -4,7 +4,7 @@ source: azure_m365 log_source: product: [azure] - service: [m365] + service: [m365, o365, office365] default_log_source: product: azure diff --git a/uncoder-core/app/translator/platforms/athena/renders/athena.py b/uncoder-core/app/translator/platforms/athena/renders/athena.py index a717d94f..a62e5b00 100644 --- a/uncoder-core/app/translator/platforms/athena/renders/athena.py +++ b/uncoder-core/app/translator/platforms/athena/renders/athena.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from app.translator.core.models.platform_details import PlatformDetails from app.translator.managers import render_manager from app.translator.platforms.athena.const import athena_details @@ -35,6 +36,9 @@ class AthenaQueryRender(SqlQueryRender): or_token = "OR" field_value_map = AthenaFieldValue(or_token=or_token) - query_pattern = "{prefix} WHERE {query} {functions}" comment_symbol = "--" is_single_line_comment = True + + @staticmethod + def _finalize_search_query(query: str) -> str: + return f"WHERE {query}" if query else "" diff --git a/uncoder-core/app/translator/platforms/base/aql/renders/aql.py b/uncoder-core/app/translator/platforms/base/aql/renders/aql.py index 6792d900..05826d08 100644 --- a/uncoder-core/app/translator/platforms/base/aql/renders/aql.py +++ b/uncoder-core/app/translator/platforms/base/aql/renders/aql.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import Union from app.translator.const import DEFAULT_VALUE_TYPE @@ -127,7 +128,6 @@ class AQLQueryRender(PlatformQueryRender): not_token = "NOT" field_value_map = AQLFieldValue(or_token=or_token) - query_pattern = "{prefix} AND {query} {functions}" def generate_prefix(self, log_source_signature: AQLLogSourceSignature, functions_prefix: str = "") -> str: # noqa: ARG002 table = str(log_source_signature) @@ -136,3 +136,7 @@ def generate_prefix(self, log_source_signature: AQLLogSourceSignature, functions def wrap_with_comment(self, value: str) -> str: return f"/* {value} */" + + @staticmethod + def _finalize_search_query(query: str) -> str: + return f"AND {query}" if query else "" diff --git a/uncoder-core/app/translator/platforms/base/aql/str_value_manager.py b/uncoder-core/app/translator/platforms/base/aql/str_value_manager.py index a5f0abdf..111ffd7d 100644 --- a/uncoder-core/app/translator/platforms/base/aql/str_value_manager.py +++ b/uncoder-core/app/translator/platforms/base/aql/str_value_manager.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + import copy from typing import ClassVar diff --git a/uncoder-core/app/translator/platforms/base/aql/tokenizer.py b/uncoder-core/app/translator/platforms/base/aql/tokenizer.py index d2bfdfb7..54a797eb 100644 --- a/uncoder-core/app/translator/platforms/base/aql/tokenizer.py +++ b/uncoder-core/app/translator/platforms/base/aql/tokenizer.py @@ -15,6 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ----------------------------------------------------------------- """ + import re from typing import ClassVar, Optional, Union diff --git a/uncoder-core/app/translator/platforms/base/lucene/renders/lucene.py b/uncoder-core/app/translator/platforms/base/lucene/renders/lucene.py index 70760930..b5994499 100644 --- a/uncoder-core/app/translator/platforms/base/lucene/renders/lucene.py +++ b/uncoder-core/app/translator/platforms/base/lucene/renders/lucene.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import Optional, Union from app.translator.const import DEFAULT_VALUE_TYPE @@ -106,8 +107,6 @@ class LuceneQueryRender(PlatformQueryRender): and_token = "AND" not_token = "NOT" - query_pattern = "{query} {functions}" - comment_symbol = "//" is_single_line_comment = True diff --git a/uncoder-core/app/translator/platforms/base/lucene/str_value_manager.py b/uncoder-core/app/translator/platforms/base/lucene/str_value_manager.py index 0b5f3b8f..9eb8e6bc 100644 --- a/uncoder-core/app/translator/platforms/base/lucene/str_value_manager.py +++ b/uncoder-core/app/translator/platforms/base/lucene/str_value_manager.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import ClassVar from app.translator.core.str_value_manager import ( diff --git a/uncoder-core/app/translator/platforms/base/lucene/tokenizer.py b/uncoder-core/app/translator/platforms/base/lucene/tokenizer.py index 45fed5e4..eb54b7ea 100644 --- a/uncoder-core/app/translator/platforms/base/lucene/tokenizer.py +++ b/uncoder-core/app/translator/platforms/base/lucene/tokenizer.py @@ -15,6 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ----------------------------------------------------------------- """ + import re from typing import ClassVar, Optional, Union diff --git a/uncoder-core/app/translator/platforms/base/spl/renders/spl.py b/uncoder-core/app/translator/platforms/base/spl/renders/spl.py index 995adf54..b2c12068 100644 --- a/uncoder-core/app/translator/platforms/base/spl/renders/spl.py +++ b/uncoder-core/app/translator/platforms/base/spl/renders/spl.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import Union from app.translator.const import DEFAULT_VALUE_TYPE @@ -78,7 +79,6 @@ class SplQueryRender(PlatformQueryRender): and_token = "AND" not_token = "NOT" - query_pattern = "{prefix} {query} {functions}" comment_symbol = "```" def wrap_with_comment(self, value: str) -> str: diff --git a/uncoder-core/app/translator/platforms/base/sql/renders/sql.py b/uncoder-core/app/translator/platforms/base/sql/renders/sql.py index ebcb21af..43904a1e 100644 --- a/uncoder-core/app/translator/platforms/base/sql/renders/sql.py +++ b/uncoder-core/app/translator/platforms/base/sql/renders/sql.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import Union from app.translator.const import DEFAULT_VALUE_TYPE @@ -76,10 +77,13 @@ class SqlQueryRender(PlatformQueryRender): and_token = "AND" not_token = "NOT" - query_pattern = "{prefix} WHERE {query} {functions}" comment_symbol = "--" is_single_line_comment = True def generate_prefix(self, log_source_signature: LogSourceSignature, functions_prefix: str = "") -> str: # noqa: ARG002 table = str(log_source_signature) if str(log_source_signature) else "eventlog" return f"SELECT * FROM {table}" + + @staticmethod + def _finalize_search_query(query: str) -> str: + return f"WHERE {query}" if query else "" diff --git a/uncoder-core/app/translator/platforms/chronicle/parsers/chronicle.py b/uncoder-core/app/translator/platforms/chronicle/parsers/chronicle.py index 7e511344..8c0e8431 100644 --- a/uncoder-core/app/translator/platforms/chronicle/parsers/chronicle.py +++ b/uncoder-core/app/translator/platforms/chronicle/parsers/chronicle.py @@ -16,7 +16,6 @@ ----------------------------------------------------------------- """ - from app.translator.core.models.platform_details import PlatformDetails from app.translator.core.models.query_container import RawQueryContainer, TokenizedQueryContainer from app.translator.core.parser import PlatformQueryParser diff --git a/uncoder-core/app/translator/platforms/chronicle/renders/chronicle.py b/uncoder-core/app/translator/platforms/chronicle/renders/chronicle.py index 63f75608..4101b825 100644 --- a/uncoder-core/app/translator/platforms/chronicle/renders/chronicle.py +++ b/uncoder-core/app/translator/platforms/chronicle/renders/chronicle.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import Union from app.translator.const import DEFAULT_VALUE_TYPE @@ -109,6 +110,5 @@ class ChronicleQueryRender(PlatformQueryRender): not_token = "not" field_value_map = ChronicleFieldValue(or_token=or_token) - query_pattern = "{query} {functions}" comment_symbol = "//" is_single_line_comment = True diff --git a/uncoder-core/app/translator/platforms/crowdstrike/parsers/crowdstrike.py b/uncoder-core/app/translator/platforms/crowdstrike/parsers/crowdstrike.py index 85b9635e..80130636 100644 --- a/uncoder-core/app/translator/platforms/crowdstrike/parsers/crowdstrike.py +++ b/uncoder-core/app/translator/platforms/crowdstrike/parsers/crowdstrike.py @@ -15,6 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ----------------------------------------------------------------- """ + from app.translator.core.models.platform_details import PlatformDetails from app.translator.managers import parser_manager from app.translator.platforms.base.spl.parsers.spl import SplQueryParser diff --git a/uncoder-core/app/translator/platforms/crowdstrike/renders/crowdstrike.py b/uncoder-core/app/translator/platforms/crowdstrike/renders/crowdstrike.py index 17ae1a15..8c6630e9 100644 --- a/uncoder-core/app/translator/platforms/crowdstrike/renders/crowdstrike.py +++ b/uncoder-core/app/translator/platforms/crowdstrike/renders/crowdstrike.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from app.translator.core.models.platform_details import PlatformDetails from app.translator.managers import render_manager from app.translator.platforms.base.spl.renders.spl import SplFieldValue, SplQueryRender @@ -31,14 +32,13 @@ class CrowdStrikeFieldValue(SplFieldValue): @render_manager.register class CrowdStrikeQueryRender(SplQueryRender): details: PlatformDetails = crowdstrike_query_details - query_pattern = "{prefix} {query} {functions}" mappings: CrowdstrikeMappings = crowdstrike_mappings - platform_functions: CrowdStrikeFunctions = crowd_strike_functions + platform_functions: CrowdStrikeFunctions = None or_token = "OR" field_value_map = CrowdStrikeFieldValue(or_token=or_token) comment_symbol = "`" - def __init__(self): - super().__init__() - self.platform_functions.manager.post_init_configure(self) + def init_platform_functions(self) -> None: + self.platform_functions = crowd_strike_functions + self.platform_functions.platform_query_render = self diff --git a/uncoder-core/app/translator/platforms/elasticsearch/parsers/detection_rule.py b/uncoder-core/app/translator/platforms/elasticsearch/parsers/detection_rule.py index 3e6a7823..dba7807a 100644 --- a/uncoder-core/app/translator/platforms/elasticsearch/parsers/detection_rule.py +++ b/uncoder-core/app/translator/platforms/elasticsearch/parsers/detection_rule.py @@ -16,7 +16,6 @@ ----------------------------------------------------------------- """ - from app.translator.core.mixins.rule import JsonRuleMixin from app.translator.core.models.platform_details import PlatformDetails from app.translator.core.models.query_container import MetaInfoContainer, RawQueryContainer diff --git a/uncoder-core/app/translator/platforms/elasticsearch/renders/detection_rule.py b/uncoder-core/app/translator/platforms/elasticsearch/renders/detection_rule.py index 4e7face5..09fad79b 100644 --- a/uncoder-core/app/translator/platforms/elasticsearch/renders/detection_rule.py +++ b/uncoder-core/app/translator/platforms/elasticsearch/renders/detection_rule.py @@ -51,7 +51,6 @@ class ElasticSearchRuleRender(ElasticSearchQueryRender): not_token = "NOT" field_value_map = ElasticSearchRuleFieldValue(or_token=or_token) - query_pattern = "{prefix} {query} {functions}" def __create_mitre_threat(self, mitre_attack: dict) -> Union[list, list[dict]]: if not mitre_attack.get("techniques"): @@ -85,13 +84,14 @@ def finalize_query( query: str, functions: str, meta_info: Optional[MetaInfoContainer] = None, - source_mapping: Optional[SourceMapping] = None, # noqa: ARG002 + source_mapping: Optional[SourceMapping] = None, not_supported_functions: Optional[list] = None, *args, # noqa: ARG002 **kwargs, # noqa: ARG002 ) -> str: query = super().finalize_query(prefix=prefix, query=query, functions=functions) rule = copy.deepcopy(ELASTICSEARCH_DETECTION_RULE) + index = source_mapping.log_source_signature.default_source.get("index") if source_mapping else None rule.update( { "query": query, @@ -105,6 +105,7 @@ def finalize_query( "tags": meta_info.tags, "threat": self.__create_mitre_threat(meta_info.mitre_attack), "false_positives": meta_info.false_positives, + "index": [index] if index else [], } ) rule_str = json.dumps(rule, indent=4, sort_keys=False, ensure_ascii=False) diff --git a/uncoder-core/app/translator/platforms/elasticsearch/renders/elast_alert.py b/uncoder-core/app/translator/platforms/elasticsearch/renders/elast_alert.py index ba1bb93b..104b8ecc 100644 --- a/uncoder-core/app/translator/platforms/elasticsearch/renders/elast_alert.py +++ b/uncoder-core/app/translator/platforms/elasticsearch/renders/elast_alert.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import Optional from app.translator.core.custom_types.meta_info import SeverityType @@ -49,7 +50,6 @@ class ElastAlertRuleRender(ElasticSearchQueryRender): not_token = "NOT" field_value_map = ElasticAlertRuleFieldValue(or_token=or_token) - query_pattern = "{prefix} {query} {functions}" def finalize_query( self, diff --git a/uncoder-core/app/translator/platforms/elasticsearch/renders/kibana.py b/uncoder-core/app/translator/platforms/elasticsearch/renders/kibana.py index 31216239..c3b6a46a 100644 --- a/uncoder-core/app/translator/platforms/elasticsearch/renders/kibana.py +++ b/uncoder-core/app/translator/platforms/elasticsearch/renders/kibana.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + import copy import json from typing import Optional diff --git a/uncoder-core/app/translator/platforms/elasticsearch/renders/xpack_watcher.py b/uncoder-core/app/translator/platforms/elasticsearch/renders/xpack_watcher.py index 551ac2c6..9a013dcf 100644 --- a/uncoder-core/app/translator/platforms/elasticsearch/renders/xpack_watcher.py +++ b/uncoder-core/app/translator/platforms/elasticsearch/renders/xpack_watcher.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + import copy import json from typing import Optional diff --git a/uncoder-core/app/translator/platforms/forti_siem/renders/forti_siem_rule.py b/uncoder-core/app/translator/platforms/forti_siem/renders/forti_siem_rule.py index bef9392b..65ca0b07 100644 --- a/uncoder-core/app/translator/platforms/forti_siem/renders/forti_siem_rule.py +++ b/uncoder-core/app/translator/platforms/forti_siem/renders/forti_siem_rule.py @@ -18,6 +18,7 @@ from typing import Optional, Union from app.translator.const import DEFAULT_VALUE_TYPE +from app.translator.core.context_vars import return_only_first_query_ctx_var from app.translator.core.custom_types.meta_info import SeverityType from app.translator.core.custom_types.tokens import GroupType, LogicalOperatorType, OperatorType from app.translator.core.custom_types.values import ValueType @@ -192,7 +193,6 @@ class FortiSiemRuleRender(PlatformQueryRender): not_token = None group_token = "(%s)" - query_pattern = "{prefix} {query}" field_value_map = FortiSiemFieldValue(or_token=or_token) @@ -273,6 +273,8 @@ def _generate_from_tokenized_query_container(self, query_container: TokenizedQue source_mapping=source_mapping, fields=mapped_fields_set, ) + if return_only_first_query_ctx_var.get() is True: + return finalized_query queries_map[source_mapping.source_id] = finalized_query return self.finalize(queries_map) @@ -301,7 +303,7 @@ def finalize_query( self, prefix: str, query: str, - functions: str, # noqa: ARG002 + functions: str, meta_info: Optional[MetaInfoContainer] = None, source_mapping: Optional[SourceMapping] = None, # noqa: ARG002 not_supported_functions: Optional[list] = None, @@ -309,7 +311,7 @@ def finalize_query( *args, # noqa: ARG002 **kwargs, # noqa: ARG002 ) -> str: - query = self.query_pattern.format(prefix=prefix, query=query).strip() + query = super().finalize_query(prefix=prefix, query=query, functions=functions) rule = FORTI_SIEM_RULE.replace("", self.generate_rule_header(meta_info)) title = meta_info.title or _AUTOGENERATED_TEMPLATE rule = rule.replace("", self.generate_rule_name(title)) diff --git a/uncoder-core/app/translator/platforms/forti_siem/str_value_manager.py b/uncoder-core/app/translator/platforms/forti_siem/str_value_manager.py index 60d7198a..1c6b34ed 100644 --- a/uncoder-core/app/translator/platforms/forti_siem/str_value_manager.py +++ b/uncoder-core/app/translator/platforms/forti_siem/str_value_manager.py @@ -2,10 +2,13 @@ Uncoder IO Community Edition License ----------------------------------------------------------------- Copyright (c) 2024 SOC Prime, Inc. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/uncoder-core/app/translator/platforms/hunters/renders/hunters.py b/uncoder-core/app/translator/platforms/hunters/renders/hunters.py index 1dc54e94..0348bfb0 100644 --- a/uncoder-core/app/translator/platforms/hunters/renders/hunters.py +++ b/uncoder-core/app/translator/platforms/hunters/renders/hunters.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from app.translator.core.models.platform_details import PlatformDetails from app.translator.managers import render_manager from app.translator.platforms.base.sql.renders.sql import SqlFieldValue, SqlQueryRender @@ -35,4 +36,7 @@ class HuntersQueryRender(SqlQueryRender): or_token = "OR" field_value_map = HuntersFieldValue(or_token=or_token) - query_pattern = "{prefix} WHERE {query} {functions}" + + @staticmethod + def _finalize_search_query(query: str) -> str: + return f"WHERE {query}" if query else "" diff --git a/uncoder-core/app/translator/platforms/logrhythm_axon/renders/logrhythm_axon_query.py b/uncoder-core/app/translator/platforms/logrhythm_axon/renders/logrhythm_axon_query.py index 9be24b73..624fa3d7 100644 --- a/uncoder-core/app/translator/platforms/logrhythm_axon/renders/logrhythm_axon_query.py +++ b/uncoder-core/app/translator/platforms/logrhythm_axon/renders/logrhythm_axon_query.py @@ -16,9 +16,11 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import Union from app.translator.const import DEFAULT_VALUE_TYPE +from app.translator.core.context_vars import return_only_first_query_ctx_var from app.translator.core.custom_types.tokens import LogicalOperatorType from app.translator.core.custom_types.values import ValueType from app.translator.core.exceptions.core import StrictPlatformException @@ -203,13 +205,16 @@ class LogRhythmAxonQueryRender(PlatformQueryRender): not_token = "NOT" field_value_map = LogRhythmAxonFieldValue(or_token=or_token) - query_pattern = "{prefix} AND {query}" mappings: LogRhythmAxonMappings = logrhythm_axon_mappings comment_symbol = "//" is_single_line_comment = True is_strict_mapping = True + @staticmethod + def _finalize_search_query(query: str) -> str: + return f"AND {query}" if query else "" + def generate_prefix(self, log_source_signature: LogSourceSignature, functions_prefix: str = "") -> str: # noqa: ARG002 return str(log_source_signature) @@ -262,6 +267,8 @@ def _generate_from_tokenized_query_container(self, query_container: TokenizedQue meta_info=query_container.meta_info, source_mapping=source_mapping, ) + if return_only_first_query_ctx_var.get() is True: + return finalized_query queries_map[source_mapping.source_id] = finalized_query return self.finalize(queries_map) diff --git a/uncoder-core/app/translator/platforms/logrhythm_axon/renders/logrhythm_axon_rule.py b/uncoder-core/app/translator/platforms/logrhythm_axon/renders/logrhythm_axon_rule.py index 7a250041..20514140 100644 --- a/uncoder-core/app/translator/platforms/logrhythm_axon/renders/logrhythm_axon_rule.py +++ b/uncoder-core/app/translator/platforms/logrhythm_axon/renders/logrhythm_axon_rule.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + import copy import json from typing import Optional diff --git a/uncoder-core/app/translator/platforms/logscale/parsers/logscale.py b/uncoder-core/app/translator/platforms/logscale/parsers/logscale.py index fd9ede79..e1015ff2 100644 --- a/uncoder-core/app/translator/platforms/logscale/parsers/logscale.py +++ b/uncoder-core/app/translator/platforms/logscale/parsers/logscale.py @@ -16,7 +16,6 @@ ----------------------------------------------------------------- """ - from app.translator.core.models.functions.base import ParsedFunctions from app.translator.core.models.platform_details import PlatformDetails from app.translator.core.models.query_container import RawQueryContainer, TokenizedQueryContainer diff --git a/uncoder-core/app/translator/platforms/logscale/parsers/logscale_alert.py b/uncoder-core/app/translator/platforms/logscale/parsers/logscale_alert.py index f9a18c01..a9cbd603 100644 --- a/uncoder-core/app/translator/platforms/logscale/parsers/logscale_alert.py +++ b/uncoder-core/app/translator/platforms/logscale/parsers/logscale_alert.py @@ -16,7 +16,6 @@ ----------------------------------------------------------------- """ - from app.translator.core.mixins.rule import JsonRuleMixin from app.translator.core.models.platform_details import PlatformDetails from app.translator.core.models.query_container import MetaInfoContainer, RawQueryContainer diff --git a/uncoder-core/app/translator/platforms/logscale/renders/logscale.py b/uncoder-core/app/translator/platforms/logscale/renders/logscale.py index a4e529ed..9cb7cf05 100644 --- a/uncoder-core/app/translator/platforms/logscale/renders/logscale.py +++ b/uncoder-core/app/translator/platforms/logscale/renders/logscale.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import Optional, Union from app.translator.const import DEFAULT_VALUE_TYPE @@ -95,18 +96,17 @@ def keywords(self, field: str, value: DEFAULT_VALUE_TYPE) -> str: class LogScaleQueryRender(PlatformQueryRender): details: PlatformDetails = logscale_query_details mappings: LogScaleMappings = logscale_mappings - platform_functions: LogScaleFunctions = log_scale_functions + platform_functions: LogScaleFunctions = None or_token = "or" and_token = "" not_token = "not" field_value_map = LogScaleFieldValue(or_token=or_token) - query_pattern = "{prefix} {query} {functions}" - def __init__(self): - super().__init__() - self.platform_functions.manager.post_init_configure(self) + def init_platform_functions(self) -> None: + self.platform_functions = log_scale_functions + self.platform_functions.platform_query_render = self def wrap_with_comment(self, value: str) -> str: return f"/* {value} */" @@ -122,10 +122,7 @@ def finalize_query( *args, # noqa: ARG002 **kwargs, # noqa: ARG002 ) -> str: - if prefix: - query = self.query_pattern.format(prefix=prefix, query=query, functions=functions) - else: - query = f"{query} {functions.lstrip()}" + query = super().finalize_query(prefix=prefix, query=query, functions=functions) query = self.wrap_query_with_meta_info(meta_info=meta_info, query=query) if not_supported_functions: rendered_not_supported = self.render_not_supported_functions(not_supported_functions) diff --git a/uncoder-core/app/translator/platforms/logscale/renders/logscale_alert.py b/uncoder-core/app/translator/platforms/logscale/renders/logscale_alert.py index 24e9142f..4b3af0fb 100644 --- a/uncoder-core/app/translator/platforms/logscale/renders/logscale_alert.py +++ b/uncoder-core/app/translator/platforms/logscale/renders/logscale_alert.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + import copy import json from typing import Optional diff --git a/uncoder-core/app/translator/platforms/microsoft/parsers/microsoft_sentinel.py b/uncoder-core/app/translator/platforms/microsoft/parsers/microsoft_sentinel.py index 746c5cb0..507c8c17 100644 --- a/uncoder-core/app/translator/platforms/microsoft/parsers/microsoft_sentinel.py +++ b/uncoder-core/app/translator/platforms/microsoft/parsers/microsoft_sentinel.py @@ -16,7 +16,6 @@ ----------------------------------------------------------------- """ - from app.translator.core.models.functions.base import ParsedFunctions from app.translator.core.models.platform_details import PlatformDetails from app.translator.core.models.query_container import RawQueryContainer, TokenizedQueryContainer diff --git a/uncoder-core/app/translator/platforms/microsoft/parsers/microsoft_sentinel_rule.py b/uncoder-core/app/translator/platforms/microsoft/parsers/microsoft_sentinel_rule.py index c0615b57..9cf400e2 100644 --- a/uncoder-core/app/translator/platforms/microsoft/parsers/microsoft_sentinel_rule.py +++ b/uncoder-core/app/translator/platforms/microsoft/parsers/microsoft_sentinel_rule.py @@ -16,7 +16,6 @@ ----------------------------------------------------------------- """ - from app.translator.core.mixins.rule import JsonRuleMixin from app.translator.core.models.platform_details import PlatformDetails from app.translator.core.models.query_container import MetaInfoContainer, RawQueryContainer diff --git a/uncoder-core/app/translator/platforms/microsoft/renders/microsoft_defender_cti.py b/uncoder-core/app/translator/platforms/microsoft/renders/microsoft_defender_cti.py index 372cb58d..621decb1 100644 --- a/uncoder-core/app/translator/platforms/microsoft/renders/microsoft_defender_cti.py +++ b/uncoder-core/app/translator/platforms/microsoft/renders/microsoft_defender_cti.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import ClassVar from app.translator.core.models.platform_details import PlatformDetails diff --git a/uncoder-core/app/translator/platforms/microsoft/renders/microsoft_sentinel.py b/uncoder-core/app/translator/platforms/microsoft/renders/microsoft_sentinel.py index cb32443a..3153f8d4 100644 --- a/uncoder-core/app/translator/platforms/microsoft/renders/microsoft_sentinel.py +++ b/uncoder-core/app/translator/platforms/microsoft/renders/microsoft_sentinel.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import Union from app.translator.const import DEFAULT_VALUE_TYPE @@ -121,22 +122,25 @@ def is_not_none(self, field: str, value: Union[str, int]) -> str: # noqa: ARG00 @render_manager.register class MicrosoftSentinelQueryRender(PlatformQueryRender): details: PlatformDetails = microsoft_sentinel_query_details - platform_functions: MicrosoftFunctions = microsoft_sentinel_functions + platform_functions: MicrosoftFunctions = None or_token = "or" and_token = "and" not_token = "not" field_value_map = MicrosoftSentinelFieldValue(or_token=or_token) - query_pattern = "{prefix} | where {query}{functions}" mappings: MicrosoftSentinelMappings = microsoft_sentinel_mappings comment_symbol = "//" is_single_line_comment = True - def __init__(self): - super().__init__() - self.platform_functions.manager.post_init_configure(self) + def init_platform_functions(self) -> None: + self.platform_functions = microsoft_sentinel_functions + self.platform_functions.platform_query_render = self def generate_prefix(self, log_source_signature: LogSourceSignature, functions_prefix: str = "") -> str: # noqa: ARG002 return str(log_source_signature) + + @staticmethod + def _finalize_search_query(query: str) -> str: + return f"| where {query}" if query else "" diff --git a/uncoder-core/app/translator/platforms/microsoft/renders/microsoft_sentinel_rule.py b/uncoder-core/app/translator/platforms/microsoft/renders/microsoft_sentinel_rule.py index 8a7089c5..e2fdb81f 100644 --- a/uncoder-core/app/translator/platforms/microsoft/renders/microsoft_sentinel_rule.py +++ b/uncoder-core/app/translator/platforms/microsoft/renders/microsoft_sentinel_rule.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + import copy import json from typing import Optional diff --git a/uncoder-core/app/translator/platforms/opensearch/renders/opensearch.py b/uncoder-core/app/translator/platforms/opensearch/renders/opensearch.py index 23808279..1d2145a7 100644 --- a/uncoder-core/app/translator/platforms/opensearch/renders/opensearch.py +++ b/uncoder-core/app/translator/platforms/opensearch/renders/opensearch.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import Union from app.translator.const import DEFAULT_VALUE_TYPE diff --git a/uncoder-core/app/translator/platforms/opensearch/renders/opensearch_rule.py b/uncoder-core/app/translator/platforms/opensearch/renders/opensearch_rule.py index 557f911e..3f68e6c6 100644 --- a/uncoder-core/app/translator/platforms/opensearch/renders/opensearch_rule.py +++ b/uncoder-core/app/translator/platforms/opensearch/renders/opensearch_rule.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + import copy import json from typing import Optional, Union @@ -49,7 +50,6 @@ class OpenSearchRuleRender(OpenSearchQueryRender): not_token = "NOT" field_value_map = OpenSearchRuleFieldValue(or_token=or_token) - query_pattern = "{prefix} {query} {functions}" def __init__(self): super().__init__() diff --git a/uncoder-core/app/translator/platforms/palo_alto/renders/cortex_xsiam.py b/uncoder-core/app/translator/platforms/palo_alto/renders/cortex_xsiam.py index c0b032e4..54f50916 100644 --- a/uncoder-core/app/translator/platforms/palo_alto/renders/cortex_xsiam.py +++ b/uncoder-core/app/translator/platforms/palo_alto/renders/cortex_xsiam.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import ClassVar, Optional, Union from app.translator.const import DEFAULT_VALUE_TYPE @@ -146,9 +147,9 @@ class CortexXQLQueryRender(PlatformQueryRender): or_token = "or" and_token = "and" not_token = "not" + query_parts_delimiter = "\n" field_value_map = CortexXQLFieldValue(or_token=or_token) - query_pattern = "{prefix} | filter {query} {functions}" comment_symbol = "//" is_single_line_comment = False @@ -171,3 +172,7 @@ def process_raw_log_field(self, field: str, field_type: str) -> Optional[str]: def generate_prefix(self, log_source_signature: CortexXQLLogSourceSignature, functions_prefix: str = "") -> str: functions_prefix = f"{functions_prefix} | " if functions_prefix else "" return f"{functions_prefix}{log_source_signature}" + + @staticmethod + def _finalize_search_query(query: str) -> str: + return f"| filter {query}" if query else "" diff --git a/uncoder-core/app/translator/platforms/palo_alto/str_value_manager.py b/uncoder-core/app/translator/platforms/palo_alto/str_value_manager.py index 7a454d13..e547f223 100644 --- a/uncoder-core/app/translator/platforms/palo_alto/str_value_manager.py +++ b/uncoder-core/app/translator/platforms/palo_alto/str_value_manager.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + import copy from app.translator.core.custom_types.values import ValueType diff --git a/uncoder-core/app/translator/platforms/qradar/renders/qradar.py b/uncoder-core/app/translator/platforms/qradar/renders/qradar.py index e7c92b76..0f06fb40 100644 --- a/uncoder-core/app/translator/platforms/qradar/renders/qradar.py +++ b/uncoder-core/app/translator/platforms/qradar/renders/qradar.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from app.translator.core.models.platform_details import PlatformDetails from app.translator.managers import render_manager from app.translator.platforms.base.aql.renders.aql import AQLFieldValue, AQLQueryRender diff --git a/uncoder-core/app/translator/platforms/sigma/escape_manager.py b/uncoder-core/app/translator/platforms/sigma/escape_manager.py index b656c4ad..c0efb332 100644 --- a/uncoder-core/app/translator/platforms/sigma/escape_manager.py +++ b/uncoder-core/app/translator/platforms/sigma/escape_manager.py @@ -7,7 +7,7 @@ class SigmaEscapeManager(EscapeManager): escape_map: ClassVar[dict[str, list[EscapeDetails]]] = { - ValueType.value: [EscapeDetails(pattern=r'([*?\\])', escape_symbols=r"\\\1")], + ValueType.value: [EscapeDetails(pattern=r"([*?\\])", escape_symbols=r"\\\1")] } diff --git a/uncoder-core/app/translator/platforms/sigma/models/compiler.py b/uncoder-core/app/translator/platforms/sigma/models/compiler.py index 5969d06c..2c0b6472 100644 --- a/uncoder-core/app/translator/platforms/sigma/models/compiler.py +++ b/uncoder-core/app/translator/platforms/sigma/models/compiler.py @@ -15,6 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ----------------------------------------------------------------- """ + from typing import Union from app.translator.core.custom_types.tokens import GroupType, LogicalOperatorType diff --git a/uncoder-core/app/translator/platforms/sigma/models/modifiers.py b/uncoder-core/app/translator/platforms/sigma/models/modifiers.py index 7ae75726..446eb310 100644 --- a/uncoder-core/app/translator/platforms/sigma/models/modifiers.py +++ b/uncoder-core/app/translator/platforms/sigma/models/modifiers.py @@ -26,7 +26,7 @@ def map_modifier(self, modifier: str) -> Identifier: return Identifier(token_type=self.modifier_map.get(modifier, modifier)) def modifier_all(self, field_name: str, modifier: str, values: Union[str, list[str]]) -> Union[tuple, list]: - if (isinstance(values, list) and len(values) == 1) or isinstance(values, str): + if (isinstance(values, list) and len(values) == 1) or isinstance(values, (str, int)): operator = self.map_modifier(modifier=modifier) values = self.convert_values_to_str_values(values, modifier) return (FieldValue(source_name=field_name, operator=operator, value=values),) @@ -80,8 +80,7 @@ def apply_modifier(self, field_name: str, modifier: list, values: Union[int, str @staticmethod def convert_values_to_str_values( - values: Union[int, str, list[Union[int, str]]], - operator: str + values: Union[int, str, list[Union[int, str]]], operator: str ) -> Union[StrValue, list[StrValue]]: if not isinstance(values, list): values = [values] diff --git a/uncoder-core/app/translator/platforms/sigma/parsers/sigma.py b/uncoder-core/app/translator/platforms/sigma/parsers/sigma.py index c5f1293b..9f2fd7ab 100644 --- a/uncoder-core/app/translator/platforms/sigma/parsers/sigma.py +++ b/uncoder-core/app/translator/platforms/sigma/parsers/sigma.py @@ -17,14 +17,13 @@ ----------------------------------------------------------------- """ - from typing import Union from app.translator.core.exceptions.core import SigmaRuleValidationException from app.translator.core.mixins.rule import YamlRuleMixin -from app.translator.core.models.field import FieldValue, Field -from app.translator.core.models.query_container import MetaInfoContainer, TokenizedQueryContainer, RawQueryContainer +from app.translator.core.models.field import Field, FieldValue from app.translator.core.models.platform_details import PlatformDetails +from app.translator.core.models.query_container import MetaInfoContainer, RawQueryContainer, TokenizedQueryContainer from app.translator.core.parser import QueryParser from app.translator.core.tokenizer import QueryTokenizer from app.translator.managers import parser_manager @@ -50,12 +49,12 @@ def __parse_false_positives(false_positives: Union[str, list[str], None]) -> lis return false_positives def _get_meta_info( - self, - rule: dict, - source_mapping_ids: list[str], - parsed_logsources: dict, - fields_tokens: list[Field], - sigma_fields_tokens: Union[list[Field], None] = None + self, + rule: dict, + source_mapping_ids: list[str], + parsed_logsources: dict, + fields_tokens: list[Field], + sigma_fields_tokens: Union[list[Field], None] = None, ) -> MetaInfoContainer: return MetaInfoContainer( title=rule.get("title"), @@ -73,7 +72,7 @@ def _get_meta_info( tags=sorted(set(rule.get("tags", []))), false_positives=self.__parse_false_positives(rule.get("falsepositives")), source_mapping_ids=source_mapping_ids, - parsed_logsources=parsed_logsources + parsed_logsources=parsed_logsources, ) def __validate_rule(self, rule: dict): @@ -97,10 +96,11 @@ def parse(self, raw_query_container: RawQueryContainer) -> TokenizedQueryContain source_mappings = self.mappings.get_suitable_source_mappings(field_names=field_names, **log_sources) QueryTokenizer.set_field_tokens_generic_names_map(field_tokens, source_mappings, self.mappings.default_mapping) sigma_fields_tokens = None - if sigma_fields := sigma_rule.get('fields'): + if sigma_fields := sigma_rule.get("fields"): sigma_fields_tokens = [Field(source_name=field) for field in sigma_fields] - QueryTokenizer.set_field_tokens_generic_names_map(sigma_fields_tokens, source_mappings, - self.mappings.default_mapping) + QueryTokenizer.set_field_tokens_generic_names_map( + sigma_fields_tokens, source_mappings, self.mappings.default_mapping + ) return TokenizedQueryContainer( tokens=tokens, meta_info=self._get_meta_info( @@ -108,6 +108,6 @@ def parse(self, raw_query_container: RawQueryContainer) -> TokenizedQueryContain source_mapping_ids=[source_mapping.source_id for source_mapping in source_mappings], sigma_fields_tokens=sigma_fields_tokens, parsed_logsources=log_sources, - fields_tokens=field_tokens - ) + fields_tokens=field_tokens, + ), ) diff --git a/uncoder-core/app/translator/platforms/sigma/renders/sigma.py b/uncoder-core/app/translator/platforms/sigma/renders/sigma.py index b0e49ee1..dc33a507 100644 --- a/uncoder-core/app/translator/platforms/sigma/renders/sigma.py +++ b/uncoder-core/app/translator/platforms/sigma/renders/sigma.py @@ -25,8 +25,8 @@ from app.translator.core.custom_types.tokens import OperatorType from app.translator.core.mapping import DEFAULT_MAPPING_NAME, SourceMapping from app.translator.core.models.field import FieldValue, Keyword -from app.translator.core.models.query_container import TokenizedQueryContainer, RawQueryContainer from app.translator.core.models.platform_details import PlatformDetails +from app.translator.core.models.query_container import RawQueryContainer, TokenizedQueryContainer from app.translator.core.render import QueryRender from app.translator.core.str_value_manager import StrValue from app.translator.managers import render_manager diff --git a/uncoder-core/app/translator/platforms/sigma/str_value_manager.py b/uncoder-core/app/translator/platforms/sigma/str_value_manager.py index c73115e7..7b1ccee1 100644 --- a/uncoder-core/app/translator/platforms/sigma/str_value_manager.py +++ b/uncoder-core/app/translator/platforms/sigma/str_value_manager.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from app.translator.core.str_value_manager import ( ReAnySymbol, ReCaretSymbol, @@ -57,7 +58,7 @@ "}": ReRightCurlyBracket, "|": ReOrOperator, ",": ReCommaSymbol, - "-": ReHyphenSymbol + "-": ReHyphenSymbol, } diff --git a/uncoder-core/app/translator/platforms/sigma/tokenizer.py b/uncoder-core/app/translator/platforms/sigma/tokenizer.py index bb1736dd..0893588f 100644 --- a/uncoder-core/app/translator/platforms/sigma/tokenizer.py +++ b/uncoder-core/app/translator/platforms/sigma/tokenizer.py @@ -28,6 +28,7 @@ class Selection: token_type = "selection" + def __init__(self, name): self.name = name @@ -142,10 +143,12 @@ def get_missed_parentheses(tokens: list[Union[Selection, Identifier]]) -> list[i missed_indices.append(index + 1) return missed_indices - def __add_parentheses_after_and_not(self, tokens: list[Union[Selection, Identifier]]) -> list[Union[Selection, Identifier]]: + def __add_parentheses_after_and_not( + self, tokens: list[Union[Selection, Identifier]] + ) -> list[Union[Selection, Identifier]]: indices = self.get_missed_parentheses(tokens=tokens) for index in reversed(indices): - tokens.insert(index+1, Identifier(token_type=GroupType.R_PAREN)) + tokens.insert(index + 1, Identifier(token_type=GroupType.R_PAREN)) tokens.insert(index, Identifier(token_type=GroupType.L_PAREN)) return tokens diff --git a/uncoder-core/app/translator/platforms/splunk/renders/splunk.py b/uncoder-core/app/translator/platforms/splunk/renders/splunk.py index 15a131b0..f9404cac 100644 --- a/uncoder-core/app/translator/platforms/splunk/renders/splunk.py +++ b/uncoder-core/app/translator/platforms/splunk/renders/splunk.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from app.translator.core.models.platform_details import PlatformDetails from app.translator.managers import render_manager from app.translator.platforms.base.spl.renders.spl import SplFieldValue, SplQueryRender @@ -36,8 +37,8 @@ class SplunkQueryRender(SplQueryRender): field_value_map = SplunkFieldValue(or_token=or_token) mappings: SplunkMappings = splunk_mappings - platform_functions: SplunkFunctions = splunk_functions + platform_functions: SplunkFunctions = None - def __init__(self): - super().__init__() - self.platform_functions.manager.post_init_configure(self) + def init_platform_functions(self) -> None: + self.platform_functions = splunk_functions + self.platform_functions.platform_query_render = self diff --git a/uncoder-core/app/translator/platforms/splunk/renders/splunk_alert.py b/uncoder-core/app/translator/platforms/splunk/renders/splunk_alert.py index 19acb808..ef0d097d 100644 --- a/uncoder-core/app/translator/platforms/splunk/renders/splunk_alert.py +++ b/uncoder-core/app/translator/platforms/splunk/renders/splunk_alert.py @@ -16,6 +16,7 @@ limitations under the License. ----------------------------------------------------------------- """ + from typing import Optional from app.translator.core.custom_types.meta_info import SeverityType