Skip to content

Commit

Permalink
Merge pull request #517 from 0RAJA/feat_rule_audit_strategy
Browse files Browse the repository at this point in the history
feat: 规则审计-策略新增/编辑-后端接口 --story=121513458
  • Loading branch information
0RAJA authored Jan 9, 2025
2 parents 6a93841 + f1977fb commit aa1d112
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 18 deletions.
Binary file modified src/backend/locale/en/LC_MESSAGES/django.mo
Binary file not shown.
16 changes: 12 additions & 4 deletions src/backend/locale/en/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-01-08 21:34+0800\n"
"POT-Creation-Date: 2025-01-09 20:42+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
Expand Down Expand Up @@ -3533,6 +3533,14 @@ msgstr "Policy type cannot be modified"
msgid "联表配置错误"
msgstr "Link table configuration error"

#, python-brace-format
msgid "规则审计SQL生成错误: {err}"
msgstr "Rule audit SQL generates errors: {err}"

#, python-format
msgid "source_field %s not found"
msgstr "source_field %s not found"

msgid "Strategy Name"
msgstr "Strategy Name"

Expand Down Expand Up @@ -3693,6 +3701,9 @@ msgstr "Map Field"
msgid "control_id and control_version are required when strategy_type is model"
msgstr "control_id and control_version are required when strategy_type is model"

msgid "Control Version not Exists"
msgstr "Control Version not Exists"

msgid "link_table_uid and link_table_version are required when strategy_type is rule and config_type is link table"
msgstr "link_table_uid and link_table_version are required when strategy_type is rule and config_type is link table"

Expand All @@ -3706,9 +3717,6 @@ msgstr "Processor Groups"
msgid "Processor Group"
msgstr "Processor Group"

msgid "Control Version not Exists"
msgstr "Control Version not Exists"

msgid "Strategy Name Duplicate"
msgstr "Strategy Name Duplicate"

Expand Down
Binary file modified src/backend/locale/zh_CN/LC_MESSAGES/django.mo
Binary file not shown.
16 changes: 12 additions & 4 deletions src/backend/locale/zh_CN/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-01-08 21:34+0800\n"
"POT-Creation-Date: 2025-01-09 20:42+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
Expand Down Expand Up @@ -3533,6 +3533,14 @@ msgstr "策略类型不可修改"
msgid "联表配置错误"
msgstr "联表配置错误"

#, python-brace-format
msgid "规则审计SQL生成错误: {err}"
msgstr "规则审计SQL生成错误: {err}"

#, python-format
msgid "source_field %s not found"
msgstr "来源字段 %s 不存在"

msgid "Strategy Name"
msgstr "策略名称"

Expand Down Expand Up @@ -3693,6 +3701,9 @@ msgstr "映射字段"
msgid "control_id and control_version are required when strategy_type is model"
msgstr "当策略类型为模型审计时,必须提供 control_id 和 control_version"

msgid "Control Version not Exists"
msgstr "控件版本不存在"

msgid "link_table_uid and link_table_version are required when strategy_type is rule and config_type is link table"
msgstr "当策略类型为规则审计并且配置类型为联表时,必须提供 link_table_uid 和 link_table_version"

Expand All @@ -3706,9 +3717,6 @@ msgstr "处理组"
msgid "Processor Group"
msgstr "处理组"

msgid "Control Version not Exists"
msgstr "控件版本不存在"

msgid "Strategy Name Duplicate"
msgstr "策略名称重复"

Expand Down
2 changes: 0 additions & 2 deletions src/backend/services/web/risk/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,9 +377,7 @@ def fields(self) -> List[Field]:

# 事件基础字段中需要映射的字段
EVENT_BASIC_MAP_FIELDS = [
EventMappingFields.EVENT_CONTENT,
EventMappingFields.RAW_EVENT_ID,
EventMappingFields.EVENT_TYPE,
EventMappingFields.EVENT_TIME,
EventMappingFields.EVENT_SOURCE,
EventMappingFields.OPERATOR,
Expand Down
10 changes: 10 additions & 0 deletions src/backend/services/web/strategy_v2/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,13 @@ class LinkTableConfigError(StrategyV2Exception):
SATUS_CODE = 400
ERROR_CODE = "009"
MESSAGE = gettext_lazy("联表配置错误")


class RuleAuditSqlGeneratorError(StrategyV2Exception):
STATUS_CODE = 400
ERROR_CODE = "010"
MESSAGE = gettext_lazy("规则审计SQL生成错误: {err}")

def __init__(self, err, *args, **kwargs):
self.MESSAGE = self.MESSAGE.format(err=err)
super().__init__(*args, **kwargs)
34 changes: 29 additions & 5 deletions src/backend/services/web/strategy_v2/handlers/rule_audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
We undertake not to change the open source license (MIT license) applicable
to the current version of the project delivered to anyone in the future.
"""
from gettext import gettext
from typing import Any, Dict, List, Optional

from bk_resource.utils.common_utils import get_md5
from django.conf import settings
from django.shortcuts import get_object_or_404
from pydantic import BaseModel
Expand All @@ -40,7 +42,10 @@
from core.sql.sql_builder import SQLGenerator
from services.web.risk.constants import EventMappingFields
from services.web.strategy_v2.constants import LinkTableTableType, RuleAuditConfigType
from services.web.strategy_v2.exceptions import LinkTableConfigError
from services.web.strategy_v2.exceptions import (
LinkTableConfigError,
RuleAuditSqlGeneratorError,
)
from services.web.strategy_v2.models import LinkTable, Strategy


Expand Down Expand Up @@ -107,6 +112,7 @@ class RuleAuditSQLBuilder:
def __init__(self, strategy: Strategy):
self.strategy = strategy
self.query_builder = BKBaseQueryBuilder()
self.display2tmp_name_map = {}

def build_system_ids_condition(self, table_name: str, system_ids: list) -> WhereCondition:
"""
Expand Down Expand Up @@ -238,6 +244,13 @@ def format(self, config_json: dict) -> SqlConfig:
where=final_where,
)

def format_alias(self, alias: str) -> str:
r"""
格式化别名为符合 bkbase 要求的字符串 [[A-Za-z_]\w*]
"""

return f"u_{get_md5(alias)}"

def build_sql(self) -> str:
"""
将规则审计策略生成 sql
Expand All @@ -253,11 +266,18 @@ def build_sql(self) -> str:
}
# 1. 生成子查询 (sub_table)
sql_config = self.format(config_json)
for field in sql_config.select_fields:
self.display2tmp_name_map[field.display_name] = self.format_alias(field.display_name)
# 格式化别名
for field in sql_config.select_fields:
field.display_name = self.display2tmp_name_map[field.display_name]
sub_table = (
RuleAuditSqlGenerator(query_builder=self.query_builder, config=sql_config).generate().as_("sub_table")
)
# 2. 构造 JSON_OBJECT(...) 参数
json_obj_args = {field.display_name: sub_table.field(field.display_name) for field in sql_config.select_fields}
display_names = self.display2tmp_name_map.keys()
fields = [sub_table.field(field.display_name) for field in sql_config.select_fields]
json_obj_args = dict(zip(display_names, fields))
# 3. 最外层 select 列表
# 3.1 JSON_OBJECT(...) => event_data
# 3.2 strategy_id => strategy_id
Expand All @@ -266,10 +286,14 @@ def build_sql(self) -> str:
make_json_expr(json_obj_args).as_(EventMappingFields.EVENT_DATA.field_name),
ValueWrapper(self.strategy.strategy_id, EventMappingFields.STRATEGY_ID.field_name),
]
for field_name, map_config in field_mapping.items():
for display_name, map_config in field_mapping.items():
if map_config.target_value:
select_fields.append(ValueWrapper(map_config.target_value, field_name))
select_fields.append(ValueWrapper(map_config.target_value, display_name))
elif map_config.source_field:
select_fields.append(sub_table.field(map_config.source_field).as_(field_name))
if map_config.source_field not in self.display2tmp_name_map:
raise RuleAuditSqlGeneratorError(gettext("source_field %s not found" % map_config.source_field))
select_fields.append(
sub_table.field(self.display2tmp_name_map[map_config.source_field]).as_(display_name)
)
# 4. 构建最终查询: from sub_table select ...
return str(self.query_builder.from_(sub_table).select(*select_fields))
2 changes: 1 addition & 1 deletion src/backend/services/web/strategy_v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class EventFieldSerializer(serializers.Serializer):


class EventBasicFieldSerializer(EventFieldSerializer):
map_config = MapFieldSerializer(label=gettext_lazy("Map Field"), required=False)
map_config = MapFieldSerializer(label=gettext_lazy("Map Field"), required=False, allow_null=True)


class StrategySerializer(serializers.Serializer):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ class TestRuleAuditSQLFormatter(TestCase):
测试 RuleAuditSQLFormatter 的 build_sql 方法, 只关注最终产出的 SQL
"""

def setUp(self):
self.patcher = patch(
"services.web.strategy_v2.handlers.rule_audit.RuleAuditSQLBuilder.format_alias", side_effect=lambda x: x
)
self.mock_method = self.patcher.start()

def tearDown(self):
self.patcher.stop()

def _build_and_assert_sql(self, strategy: Strategy, expected_sql: str, mock_link_table_obj=None):
formatter = RuleAuditSQLBuilder(strategy)
if mock_link_table_obj:
Expand Down Expand Up @@ -197,15 +206,15 @@ def test_link_table_simple(self, mock_get_obj):
"where": None,
}
event_basic_field_configs = [
{"field_name": "operator_name", "map_config": {"source_field": "username", "target_value": None}},
{"field_name": "operator_name", "map_config": {"source_field": "事件ID", "target_value": None}},
{"field_name": "bk_biz_id", "map_config": {"target_value": "123"}},
]
strategy = Strategy(strategy_id=999, configs=config_json, event_basic_field_configs=event_basic_field_configs)

expected_sql = (
"SELECT "
"udf_build_origin_data('事件ID',CONCAT_WS('',CAST(`sub_table`.`事件ID` AS STRING))) "
"`event_data`,999 `strategy_id`,`sub_table`.`username` `operator_name`,'123' `bk_biz_id` "
"`event_data`,999 `strategy_id`,`sub_table`.`事件ID` `operator_name`,'123' `bk_biz_id` "
"FROM ("
"SELECT `log_rt_1`.`event_id` `事件ID` "
"FROM log_rt_1 `log_rt_1` "
Expand Down

0 comments on commit aa1d112

Please sign in to comment.