Skip to content

Commit

Permalink
Merge pull request #516 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 31658d1 + 7afc132 commit 6a93841
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 18 deletions.
6 changes: 5 additions & 1 deletion src/backend/core/sql/sql_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
class SQLGenerator:
"""SQL 生成器"""

table_cls = Table

def __init__(self, query_builder: QueryBuilder, config: SqlConfig):
"""
初始化生成器
Expand All @@ -64,7 +66,9 @@ def _register_tables(self):
register_tables[alias] = table

# 更新 table_map 映射
self.table_map.update({alias: Table(table.table_name).as_(alias) for alias, table in register_tables.items()})
self.table_map.update(
{alias: self.table_cls(table.table_name).as_(alias) for alias, table in register_tables.items()}
)

def _get_table(self, table: Union[str, SqlTable]) -> Table:
"""根据表名获取 Table 对象"""
Expand Down
20 changes: 17 additions & 3 deletions src/backend/services/web/strategy_v2/handlers/rule_audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@
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 typing import Dict, List, Optional
from typing import Any, Dict, List, Optional

from django.conf import settings
from django.shortcuts import get_object_or_404
from pydantic import BaseModel
from pypika import Table as PyPikaTable
from pypika import functions as fn
from pypika.terms import Function, Term, ValueWrapper

Expand All @@ -43,6 +44,17 @@
from services.web.strategy_v2.models import LinkTable, Strategy


class RuleAuditTable(PyPikaTable):
def get_sql(self, **kwargs: Any) -> str:
kwargs["quote_char"] = None
kwargs["alias_quote_char"] = "`"
return super().get_sql(**kwargs)


class RuleAuditSqlGenerator(SQLGenerator):
table_cls = RuleAuditTable


class UdfBuildOriginData(Function):
""" """

Expand Down Expand Up @@ -87,7 +99,7 @@ class FieldMap(BaseModel):
target_value: Optional[str] = None # 固定值


class RuleAuditSQLGenerator:
class RuleAuditSQLBuilder:
"""
规则审计 SQL 生成器
"""
Expand Down Expand Up @@ -241,7 +253,9 @@ def build_sql(self) -> str:
}
# 1. 生成子查询 (sub_table)
sql_config = self.format(config_json)
sub_table = SQLGenerator(query_builder=self.query_builder, config=sql_config).generate().as_("sub_table")
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}
# 3. 最外层 select 列表
Expand Down
4 changes: 2 additions & 2 deletions src/backend/services/web/strategy_v2/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
StrategyPendingError,
StrategyTypeCanNotChange,
)
from services.web.strategy_v2.handlers.rule_audit import RuleAuditSQLGenerator
from services.web.strategy_v2.handlers.rule_audit import RuleAuditSQLBuilder
from services.web.strategy_v2.models import (
LinkTable,
LinkTableTag,
Expand Down Expand Up @@ -166,7 +166,7 @@ def build_rule_audit_sql(self, strategy: Strategy) -> str:
构建规则审计SQL
"""

return RuleAuditSQLGenerator(strategy).build_sql()
return RuleAuditSQLBuilder(strategy).build_sql()


class CreateStrategy(StrategyV2Base):
Expand Down
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 @@ -905,7 +905,7 @@ class RuleAuditDataSourceSerializer(serializers.Serializer):
system_ids = serializers.ListField(
label=gettext_lazy("System ID"), child=serializers.CharField(), required=False, allow_empty=True
)
link_table = RuleAuditLinkTableSerializer(label=gettext_lazy("Link Table"), required=False)
link_table = RuleAuditLinkTableSerializer(label=gettext_lazy("Link Table"), required=False, allow_null=True)
display_name = serializers.CharField(label=gettext_lazy("Display Name"), required=False)

def validate(self, attrs):
Expand Down
22 changes: 11 additions & 11 deletions src/backend/tests/test_strategy_v2/test_rule_audit_sql_formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

from services.web.strategy_v2.constants import LinkTableTableType, RuleAuditConfigType
from services.web.strategy_v2.exceptions import LinkTableConfigError
from services.web.strategy_v2.handlers.rule_audit import RuleAuditSQLGenerator
from services.web.strategy_v2.handlers.rule_audit import RuleAuditSQLBuilder
from services.web.strategy_v2.models import Strategy
from tests.base import TestCase

Expand All @@ -32,7 +32,7 @@ class TestRuleAuditSQLFormatter(TestCase):
"""

def _build_and_assert_sql(self, strategy: Strategy, expected_sql: str, mock_link_table_obj=None):
formatter = RuleAuditSQLGenerator(strategy)
formatter = RuleAuditSQLBuilder(strategy)
if mock_link_table_obj:
with patch(
"services.web.strategy_v2.handlers.rule_audit.get_object_or_404", return_value=mock_link_table_obj
Expand Down Expand Up @@ -72,7 +72,7 @@ def test_single_table_no_where_no_system_ids(self):
"`event_data`,200 `strategy_id` "
"FROM ("
"SELECT `simple_rt`.`fieldA` `字段A` "
"FROM `simple_rt` `simple_rt`) `sub_table`"
"FROM simple_rt `simple_rt`) `sub_table`"
)
self._build_and_assert_sql(strategy, expected_sql)

Expand Down Expand Up @@ -116,7 +116,7 @@ def test_single_table_with_where_and_system_ids(self):
"`event_data`,101 `strategy_id` "
"FROM ("
"SELECT `test_rt_id`.`event_id` `事件ID` "
"FROM `test_rt_id` `test_rt_id` "
"FROM test_rt_id `test_rt_id` "
"WHERE `test_rt_id`.`username`='admin' AND `test_rt_id`.`system_id` IN ('sys_1','sys_2')) `sub_table`"
)
self._build_and_assert_sql(strategy, expected_sql)
Expand Down Expand Up @@ -157,7 +157,7 @@ def test_single_table_with_field_mapping(self):
"udf_build_origin_data('列A|!@#$%^&*|列B',"
"CONCAT_WS('',CAST(`sub_table`.`列A` AS STRING),'|!@#$%^&*|',CAST(`sub_table`.`列B` AS STRING))) "
"`event_data`,300 `strategy_id`,'abcdef' `fixed_col`,`sub_table`.`列B` `mapped_col` "
"FROM (SELECT `my_rt`.`colA` `列A`,`my_rt`.`colB` `列B` FROM `my_rt` `my_rt`) `sub_table`"
"FROM (SELECT `my_rt`.`colA` `列A`,`my_rt`.`colB` `列B` FROM my_rt `my_rt`) `sub_table`"
)
self._build_and_assert_sql(strategy, expected_sql)

Expand Down Expand Up @@ -208,8 +208,8 @@ def test_link_table_simple(self, mock_get_obj):
"`event_data`,999 `strategy_id`,`sub_table`.`username` `operator_name`,'123' `bk_biz_id` "
"FROM ("
"SELECT `log_rt_1`.`event_id` `事件ID` "
"FROM `log_rt_1` `log_rt_1` "
"LEFT JOIN `asset_rt_2` `asset_rt_2` "
"FROM log_rt_1 `log_rt_1` "
"LEFT JOIN asset_rt_2 `asset_rt_2` "
"ON `log_rt_1`.`event_id`=`asset_rt_2`.`resource_id` "
"WHERE `log_rt_1`.`system_id` "
"IN ('sys_111')) `sub_table`"
Expand All @@ -235,7 +235,7 @@ def test_link_table_config_empty_links(self):

with patch("services.web.strategy_v2.handlers.rule_audit.get_object_or_404", return_value=mock_link_table_obj):
with self.assertRaises(LinkTableConfigError):
RuleAuditSQLGenerator(strategy).build_sql()
RuleAuditSQLBuilder(strategy).build_sql()

def test_json_with_mixed_columns_and_values(self):
"""
Expand Down Expand Up @@ -274,7 +274,7 @@ def test_json_with_mixed_columns_and_values(self):
"'列A|!@#$%^&*|列B',"
"CONCAT_WS('',CAST(`sub_table`.`列A` AS STRING),'|!@#$%^&*|',CAST(`sub_table`.`列B` AS STRING))) "
"`event_data`,400 `strategy_id`,'固定值' `fixed_value`,`sub_table`.`列A` `mapped_col` "
"FROM (SELECT `mixed_rt`.`colA` `列A`,`mixed_rt`.`colB` `列B` FROM `mixed_rt` `mixed_rt`) `sub_table`"
"FROM (SELECT `mixed_rt`.`colA` `列A`,`mixed_rt`.`colB` `列B` FROM mixed_rt `mixed_rt`) `sub_table`"
)
self._build_and_assert_sql(strategy, expected_sql)

Expand Down Expand Up @@ -305,7 +305,7 @@ def test_json_with_special_characters(self):
"SELECT "
"udf_build_origin_data('列A',CONCAT_WS('',CAST(`sub_table`.`列A` AS STRING))) "
"`event_data`,500 `strategy_id`,'值含\"特殊字符\\\"和反斜杠' `fixed_col` "
"FROM (SELECT `special_char_rt`.`colA` `列A` FROM `special_char_rt` `special_char_rt`) `sub_table`"
"FROM (SELECT `special_char_rt`.`colA` `列A` FROM special_char_rt `special_char_rt`) `sub_table`"
)
self._build_and_assert_sql(strategy, expected_sql)

Expand Down Expand Up @@ -342,7 +342,7 @@ def test_nested_json_structure(self):
"SELECT "
"udf_build_origin_data('列A',CONCAT_WS('',CAST(`sub_table`.`列A` AS STRING))) "
"`event_data`,600 `strategy_id` "
"FROM (SELECT `nested_rt`.`colA` `列A` FROM `nested_rt` `nested_rt`) `sub_table`"
"FROM (SELECT `nested_rt`.`colA` `列A` FROM nested_rt `nested_rt`) `sub_table`"
)
self._build_and_assert_sql(strategy, expected_sql)

Expand Down

0 comments on commit 6a93841

Please sign in to comment.