Skip to content

Commit f9d39b5

Browse files
committed
gis-9071 developing falco
1 parent f5d1c0d commit f9d39b5

File tree

5 files changed

+141
-65
lines changed

5 files changed

+141
-65
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from app.translator.platforms.falco.renders.falco import FalcoRuleRender # noqa: F401
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from typing import ClassVar
2+
3+
from app.translator.core.custom_types.values import ValueType
4+
from app.translator.core.escape_manager import EscapeManager
5+
from app.translator.core.models.escape_details import EscapeDetails
6+
7+
8+
class FalcoRuleEscapeManager(EscapeManager):
9+
escape_map: ClassVar[dict[str, list[EscapeDetails]]] = {
10+
ValueType.regex_value: [
11+
EscapeDetails(pattern=r"([$^*+()\[\]{}|.?\-\\])", escape_symbols=r"\\\1"),
12+
EscapeDetails(pattern=r"(')", escape_symbols=r"'\1"),
13+
]
14+
}
15+
16+
17+
falco_rule_escape_manager = FalcoRuleEscapeManager()

uncoder-core/app/translator/platforms/falco/mapping.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33

44

55
class FalcoRuleLogSourceSignature(LogSourceSignature):
6+
def __str__(self) -> str:
7+
return ""
68

79
def is_suitable(self) -> bool:
810
return True
911

1012

1113
class FalcoRuleMappings(BasePlatformMappings):
12-
13-
def prepare_log_source_signature(self, mapping: dict) -> FalcoRuleLogSourceSignature:
14+
def prepare_log_source_signature(self, mapping: dict) -> FalcoRuleLogSourceSignature: # noqa: ARG002
1415
return FalcoRuleLogSourceSignature()
1516

1617

uncoder-core/app/translator/platforms/falco/renders/falco.py

Lines changed: 93 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -16,75 +16,86 @@
1616
limitations under the License.
1717
-----------------------------------------------------------------
1818
"""
19-
from typing import Optional
19+
from typing import ClassVar, Optional
2020

2121
import yaml
2222

2323
from app.translator.const import DEFAULT_VALUE_TYPE
24+
from app.translator.core.custom_types.values import ValueType
2425
from app.translator.core.mapping import LogSourceSignature, SourceMapping
2526
from app.translator.core.models.platform_details import PlatformDetails
2627
from app.translator.core.models.query_container import MetaInfoContainer
28+
from app.translator.core.models.query_tokens.field import Field
2729
from app.translator.core.render import BaseFieldValueRender, PlatformQueryRender
2830
from app.translator.core.str_value_manager import StrValueManager
2931
from app.translator.managers import render_manager
3032
from app.translator.platforms.falco.const import falco_rule_details
31-
from app.translator.platforms.falco.mapping import falco_rule_mappings, FalcoRuleMappings
33+
from app.translator.platforms.falco.mapping import FalcoRuleMappings, falco_rule_mappings
34+
from app.translator.platforms.falco.str_value_manager import falco_rule_str_value_manager
3235

3336

34-
class FalcoFieldValueRender(BaseFieldValueRender):
37+
class FalcoRuleFieldValueRender(BaseFieldValueRender):
3538
details = falco_rule_details
36-
str_value_manager: StrValueManager = None
37-
#
38-
# def equal_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str: # noqa: ARG002
39-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.EQ.capitalize())
40-
41-
# def not_equal_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str: # noqa: ARG002
42-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.NOT_EQ.capitalize())
43-
#
44-
# def less_modifier(self, field: str, value: Union[int, str]) -> str: # noqa: ARG002
45-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.LT.capitalize())
46-
#
47-
# def less_or_equal_modifier(self, field: str, value: Union[int, str]) -> str: # noqa: ARG002
48-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.LTE.capitalize())
49-
#
50-
# def greater_modifier(self, field: str, value: Union[int, str]) -> str: # noqa: ARG002
51-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.GT.capitalize())
52-
#
53-
# def greater_or_equal_modifier(self, field: str, value: Union[int, str]) -> str: # noqa: ARG002
54-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.GTE.capitalize())
55-
#
56-
# def contains_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str: # noqa: ARG002
57-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.CONTAINS.capitalize())
58-
#
59-
# def not_contains_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str: # noqa: ARG002
60-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.NOT_CONTAINS.capitalize())
61-
#
62-
# def endswith_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str: # noqa: ARG002
63-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.ENDSWITH.capitalize())
64-
#
65-
# def not_endswith_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str: # noqa: ARG002
66-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.NOT_ENDSWITH.capitalize())
67-
#
68-
# def startswith_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str: # noqa: ARG002
69-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.STARTSWITH.capitalize())
70-
#
71-
# def not_startswith_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str: # noqa: ARG002
72-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.NOT_STARTSWITH.capitalize())
73-
#
74-
# def regex_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str: # noqa: ARG002
75-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.REGEX.capitalize())
76-
#
77-
# def not_regex_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str: # noqa: ARG002
78-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.NOT_REGEX.capitalize())
79-
#
80-
# def keywords(self, field: str, value: DEFAULT_VALUE_TYPE) -> str: # noqa: ARG002
81-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.KEYWORD.capitalize())
82-
#
83-
# def is_none(self, field: str, value: DEFAULT_VALUE_TYPE) -> str: # noqa: ARG002
84-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.IS_NONE.capitalize())
85-
#
86-
# def is_not_none(self, field: str, value: DEFAULT_VALUE_TYPE) -> str: # noqa: ARG002
87-
# raise UnsupportedRenderMethod(platform_name=self.details.name, method=OperatorType.IS_NOT_NONE.capitalize())
39+
str_value_manager: StrValueManager = falco_rule_str_value_manager
40+
41+
@staticmethod
42+
def _wrap_str_value(value: str) -> str:
43+
return f'"{value}"'
44+
45+
@staticmethod
46+
def _wrap_int_value(value: str) -> str:
47+
return f'"{value}"'
48+
49+
def equal_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str:
50+
if isinstance(value, list):
51+
return f"({self.or_token.join([self.equal_modifier(field=field, value=v) for v in value])})"
52+
return f"{field} = {self._pre_process_value(field, value, wrap_str=True)}"
53+
54+
def not_equal_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str:
55+
if isinstance(value, list):
56+
return f"({self.or_token.join([self.not_equal_modifier(field=field, value=v) for v in value])})"
57+
return f"{field} != {self._pre_process_value(field, value, wrap_str=True)}"
58+
59+
def less_modifier(self, field: str, value: int) -> str:
60+
return f"{field} < {self._pre_process_value(field, value)}"
61+
62+
def less_or_equal_modifier(self, field: str, value: int) -> str:
63+
return f"{field} <= {self._pre_process_value(field, value)}"
64+
65+
def greater_modifier(self, field: str, value: int) -> str:
66+
return f"{field} > {self._pre_process_value(field, value)}"
67+
68+
def greater_or_equal_modifier(self, field: str, value: int) -> str:
69+
return f"{field} >= {self._pre_process_value(field, value)}"
70+
71+
def contains_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str:
72+
if isinstance(value, list):
73+
return f"({self.or_token.join([self.contains_modifier(field=field, value=v) for v in value])})"
74+
value = self._pre_process_value(field, value, wrap_str=True, wrap_int=True)
75+
return f"{field} contains {value}"
76+
77+
def endswith_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str:
78+
if isinstance(value, list):
79+
return f"({self.or_token.join([self.endswith_modifier(field=field, value=v) for v in value])})"
80+
value = self._pre_process_value(field, value, wrap_str=True, wrap_int=True)
81+
return f"{field} endswith {value}"
82+
83+
def startswith_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str:
84+
if isinstance(value, list):
85+
return f"({self.or_token.join([self.startswith_modifier(field=field, value=v) for v in value])})"
86+
value = self._pre_process_value(field, value, wrap_str=True, wrap_int=True)
87+
return f"{field} startswith {value}"
88+
89+
def regex_modifier(self, field: str, value: DEFAULT_VALUE_TYPE) -> str:
90+
if isinstance(value, list):
91+
return f"({self.or_token.join(self.regex_modifier(field=field, value=v) for v in value)})"
92+
regex_str = self._pre_process_value(field, value, value_type=ValueType.regex_value)
93+
return f"{field} regex '{regex_str}'"
94+
95+
def is_none(self, field: str, value: DEFAULT_VALUE_TYPE) -> str:
96+
if isinstance(value, list):
97+
return f"({self.or_token.join(self.is_none(field=field, value=v) for v in value)})"
98+
return f"{field} exists"
8899

89100

90101
@render_manager.register
@@ -98,32 +109,51 @@ class FalcoRuleRender(PlatformQueryRender):
98109

99110
comment_symbol = "//"
100111

101-
field_value_render = FalcoFieldValueRender(or_token=or_token)
112+
field_value_render = FalcoRuleFieldValueRender(or_token=or_token)
113+
114+
priority_map: ClassVar[dict[str, str]] = {
115+
"unspecified": "NOTICE",
116+
"info": "INFORMATIONAL",
117+
"low": "WARNING",
118+
"medium": "ERROR",
119+
"high": "ERROR",
120+
"critical": "CRITICAL",
121+
}
102122

103123
def generate_prefix(self, log_source_signature: Optional[LogSourceSignature], functions_prefix: str = "") -> str: # noqa: ARG002
104124
return ""
105125

126+
def generate_output(self, fields: list[Field], unmapped_fields: list[str], source_mapping: SourceMapping) -> str:
127+
extra_fields = [
128+
field.source_name
129+
if field.source_name in unmapped_fields
130+
else source_mapping.fields_mapping.get_platform_field_name(generic_field_name=field.source_name)
131+
for field in fields
132+
]
133+
extra_fields = [f"{field.replace('.', '_')}=%{field}" for field in extra_fields]
134+
return f"shell in a container (container_name=%container.name {' '.join(extra_fields)})"
106135

107136
def finalize_query(
108137
self,
109138
prefix: str,
110139
query: str,
111140
functions: str,
112141
meta_info: Optional[MetaInfoContainer] = None,
113-
source_mapping: Optional[SourceMapping] = None, # noqa: ARG002
142+
source_mapping: Optional[SourceMapping] = None,
114143
not_supported_functions: Optional[list] = None,
115144
unmapped_fields: Optional[list[str]] = None,
116145
*args, # noqa: ARG002
117146
**kwargs, # noqa: ARG002
118147
) -> str:
119-
query = super().finalize_query(prefix=prefix, query=query, functions=functions)
120-
default_output = "shell in a container (user=%user.name container_id=%container.id container_name=%container.name)"
148+
query = self._join_query_parts(prefix, query, functions)
121149
rule = {
122150
"rule": meta_info.title or "Falco Rule",
123151
"condition": query,
124152
"desc": meta_info.description or "Falco Rule",
125-
"output": default_output,
126-
"priority": "alert",
153+
"output": self.generate_output(meta_info.query_fields, unmapped_fields or [], source_mapping),
154+
"priority": self.priority_map.get(meta_info.severity or "medium"),
127155
}
128-
rule = yaml.dump(rule, default_flow_style=False, sort_keys=False)
129-
return rule
156+
rule_str = yaml.dump(rule, default_flow_style=False, sort_keys=False)
157+
rule_str = self.wrap_with_meta_info(rule_str, meta_info)
158+
rule_str = self.wrap_with_unmapped_fields(rule_str, unmapped_fields)
159+
return self.wrap_with_not_supported_functions(rule_str, not_supported_functions)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""
2+
Uncoder IO Community Edition License
3+
-----------------------------------------------------------------
4+
Copyright (c) 2024 SOC Prime, Inc.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
-----------------------------------------------------------------
18+
"""
19+
from app.translator.core.str_value_manager import StrValueManager
20+
from app.translator.platforms.falco.escape_manager import FalcoRuleEscapeManager, falco_rule_escape_manager
21+
22+
23+
class FalcoRuleStrValueManager(StrValueManager):
24+
escape_manager: FalcoRuleEscapeManager = falco_rule_escape_manager
25+
26+
27+
falco_rule_str_value_manager = FalcoRuleStrValueManager()

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy