Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 规则审计-联表管理-后端接口 --story=121324647 #543

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/backend/apps/permission/handlers/drf.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def has_permission(self, request, view):
if not self.actions:
return True

client = Permission()
client = Permission(request=request)
return any([client.is_allowed(action=action) for action in self.actions])


Expand Down
Binary file modified src/backend/locale/en/LC_MESSAGES/django.mo
Binary file not shown.
14 changes: 13 additions & 1 deletion 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-16 16:23+0800\n"
"POT-Creation-Date: 2025-01-20 20:33+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 @@ -3647,6 +3647,9 @@ msgstr "List Tables"
msgid "Get RT Fields"
msgstr "Get RT Fields"

msgid "Bulk Get RT Fields"
msgstr "Bulk Get RT Fields"

msgid "Get Strategy Status"
msgstr "Get Strategy Status"

Expand Down Expand Up @@ -3853,6 +3856,12 @@ msgstr "Plan variables"
msgid "Table ID"
msgstr "Table ID"

msgid "Table IDS"
msgstr "Table IDS"

msgid "Multiple separated by commas"
msgstr "Multiple separated by commas"

msgid "value"
msgstr "value"

Expand Down Expand Up @@ -3917,6 +3926,9 @@ msgstr "Link Table Configuration"
msgid "逗号分隔的标签ID列表"
msgstr "Comma-separated tag ID list"

msgid "Need Update Strategy"
msgstr "Need Update Strategy"

msgid "Link Table Count"
msgstr "Link Table Count"

Expand Down
Binary file modified src/backend/locale/zh_CN/LC_MESSAGES/django.mo
Binary file not shown.
14 changes: 13 additions & 1 deletion 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-16 16:23+0800\n"
"POT-Creation-Date: 2025-01-20 20:33+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 @@ -3647,6 +3647,9 @@ msgstr "获取结果表列表"
msgid "Get RT Fields"
msgstr "获取RT字段"

msgid "Bulk Get RT Fields"
msgstr "批量获取RT字段"

msgid "Get Strategy Status"
msgstr "获取策略状态"

Expand Down Expand Up @@ -3853,6 +3856,12 @@ msgstr "方案参数"
msgid "Table ID"
msgstr "结果表ID"

msgid "Table IDS"
msgstr "结果表IDS"

msgid "Multiple separated by commas"
msgstr "多个以逗号分隔"

msgid "value"
msgstr "值"

Expand Down Expand Up @@ -3901,6 +3910,9 @@ msgstr "联表配置"
msgid "逗号分隔的标签ID列表"
msgstr "逗号分隔的标签ID列表"

msgid "Need Update Strategy"
msgstr "是否存在需要更新的策略"

msgid "Link Table Count"
msgstr "联表数"

Expand Down
7 changes: 0 additions & 7 deletions src/backend/services/web/risk/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,13 +368,6 @@ def fields(self) -> List[Field]:
RISK_DATA = Field(field_name="risk_data", alias_name=gettext_lazy("拓展数据"))


# 事件排除字段
EVENT_BASIC_EXCLUDE_FIELDS = [
EventMappingFields.EVENT_ID,
EventMappingFields.EVENT_EVIDENCE,
EventMappingFields.EVENT_DATA,
]

# 事件基础字段中需要映射的字段
EVENT_BASIC_MAP_FIELDS = [
EventMappingFields.RAW_EVENT_ID,
Expand Down
32 changes: 32 additions & 0 deletions src/backend/services/web/strategy_v2/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,35 @@ class Meta:
verbose_name = gettext_lazy("Link Table Tag")
verbose_name_plural = verbose_name
ordering = ["-id"]


class LinkTableAuditInstance(AuditInstance):
"""
Link Table Audit Instance
"""

@property
def instance_id(self):
"""
实例ID
@rtype: str
"""
return getattr(self.instance, "uid", DEFAULT_EMPTY_VALUE)

@property
def instance_name(self):
"""
实例名
@rtype: str
"""
return getattr(self.instance, "name", DEFAULT_EMPTY_VALUE)

@property
def instance_data(self):
"""
实例信息 JSON
@rtype: dict
"""
from services.web.strategy_v2.serializers import LinkTableInfoSerializer

return LinkTableInfoSerializer(self.instance).data
105 changes: 73 additions & 32 deletions src/backend/services/web/strategy_v2/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@
from functools import cached_property
from typing import List, Optional

from bk_resource import api, resource
from bk_resource import CacheResource, api, resource
from bk_resource.base import Empty
from bk_resource.exceptions import APIRequestError
from bk_resource.utils.cache import CacheTypeItem
from blueapps.utils.request_provider import get_local_request, get_request_username
from django.conf import settings
from django.db import transaction
from django.db.models import Count, Q, QuerySet
from django.db.models.aggregates import Min
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.utils.translation import gettext, gettext_lazy
Expand Down Expand Up @@ -61,7 +63,7 @@
)
from services.web.analyze.controls.base import BaseControl
from services.web.analyze.tasks import call_controller
from services.web.risk.constants import EVENT_BASIC_EXCLUDE_FIELDS, EventMappingFields
from services.web.risk.constants import EventMappingFields
from services.web.risk.models import Risk
from services.web.risk.permissions import RiskViewPermission
from services.web.strategy_v2.constants import (
Expand Down Expand Up @@ -96,12 +98,15 @@
from services.web.strategy_v2.handlers.rule_audit import RuleAuditSQLBuilder
from services.web.strategy_v2.models import (
LinkTable,
LinkTableAuditInstance,
LinkTableTag,
Strategy,
StrategyAuditInstance,
StrategyTag,
)
from services.web.strategy_v2.serializers import (
BulkGetRTFieldsRequestSerializer,
BulkGetRTFieldsResponseSerializer,
CreateLinkTableRequestSerializer,
CreateLinkTableResponseSerializer,
CreateStrategyRequestSerializer,
Expand All @@ -117,6 +122,7 @@
GetStrategyFieldValueRequestSerializer,
GetStrategyFieldValueResponseSerializer,
GetStrategyStatusRequestSerializer,
LinkTableInfoSerializer,
ListLinkTableAllResponseSerializer,
ListLinkTableRequestSerializer,
ListLinkTableResponseSerializer,
Expand Down Expand Up @@ -679,21 +685,12 @@ def perform_request(self, validated_request_data):
}


class ListTables(StrategyV2Base):
class ListTables(StrategyV2Base, CacheResource):
name = gettext_lazy("List Tables")
RequestSerializer = ListTablesRequestSerializer
cache_type = CacheTypeItem(key="ListTables", timeout=60, user_related=False)

def perform_request(self, validated_request_data):
# check permission
if not ActionPermission(
actions=[
ActionEnum.CREATE_STRATEGY,
ActionEnum.LIST_STRATEGY,
ActionEnum.EDIT_STRATEGY,
ActionEnum.DELETE_STRATEGY,
]
).has_permission(request=get_local_request(), view=self):
return []
return TableHandler(**validated_request_data).list_tables()


Expand All @@ -704,16 +701,6 @@ class GetRTFields(StrategyV2Base):
many_response_data = True

def perform_request(self, validated_request_data):
# check permission
if not ActionPermission(
actions=[
ActionEnum.CREATE_STRATEGY,
ActionEnum.LIST_STRATEGY,
ActionEnum.EDIT_STRATEGY,
ActionEnum.DELETE_STRATEGY,
]
).has_permission(request=get_local_request(), view=self):
return []
fields = api.bk_base.get_rt_fields(result_table_id=validated_request_data["table_id"])
return [
{
Expand All @@ -725,6 +712,25 @@ def perform_request(self, validated_request_data):
]


class BulkGetRTFields(StrategyV2Base):
name = gettext_lazy("Bulk Get RT Fields")
RequestSerializer = BulkGetRTFieldsRequestSerializer
ResponseSerializer = BulkGetRTFieldsResponseSerializer
many_response_data = True

def perform_request(self, validated_request_data):
table_ids = validated_request_data["table_ids"]
bulk_request_params = [{"table_id": table_id} for table_id in table_ids]
bulk_resp = resource.strategy_v2.get_rt_fields.bulk_request(bulk_request_params)
return [
{
"table_id": params["table_id"],
"fields": resp,
}
for params, resp in zip(bulk_request_params, bulk_resp)
]


class GetStrategyStatus(StrategyV2Base):
name = gettext_lazy("Get Strategy Status")
RequestSerializer = GetStrategyStatusRequestSerializer
Expand Down Expand Up @@ -754,8 +760,15 @@ def get_event_basic_field_configs(self, risk: Optional[Risk], has_permission: bo
description="",
example=getattr(risk, field.field_name, "") if risk and has_permission else "",
)
for field in EventMappingFields().fields
if field not in EVENT_BASIC_EXCLUDE_FIELDS
for field in [
EventMappingFields.RAW_EVENT_ID,
EventMappingFields.OPERATOR,
EventMappingFields.EVENT_TIME,
EventMappingFields.EVENT_SOURCE,
EventMappingFields.STRATEGY_ID,
EventMappingFields.EVENT_CONTENT,
EventMappingFields.EVENT_TYPE,
]
]

def get_event_data_field_configs(self, risk: Optional[Risk], has_permission: bool) -> List[EventInfoField]:
Expand Down Expand Up @@ -825,6 +838,11 @@ def perform_request(self, validated_request_data):
class LinkTableBase(AuditMixinResource, abc.ABC):
tags = ["LinkTable"]

def add_audit_instance_to_context(self, link_table: LinkTable, old_link_table: Optional[dict] = None):
if old_link_table:
setattr(link_table, "instance_origin_data", old_link_table)
super().add_audit_instance_to_context(instance=LinkTableAuditInstance(link_table))

def _save_tags(self, link_table_uid: str, tag_names: list) -> None:
LinkTableTag.objects.filter(link_table_uid=link_table_uid).delete()
if not tag_names:
Expand Down Expand Up @@ -852,6 +870,8 @@ def create_link_table(self, validated_request_data) -> LinkTable:

def perform_request(self, validated_request_data):
link_table = self.create_link_table(validated_request_data)
# audit
self.add_audit_instance_to_context(link_table)
# auth
username = get_request_username()
if username:
Expand All @@ -877,6 +897,8 @@ def update_link_table(self, validated_request_data) -> LinkTable:
link_table = LinkTable.last_version_link_table(uid=uid)
if not link_table:
raise Http404(gettext("LinkTable not found: %s") % uid)
# old link_table
old_link_table = LinkTableInfoSerializer(link_table).data
# 更新或创建新版本联表
need_update_config = "config" in validated_request_data.keys()
if not need_update_config:
Expand All @@ -899,6 +921,8 @@ def update_link_table(self, validated_request_data) -> LinkTable:
# save tag
if not isinstance(tags, Empty):
self._save_tags(link_table_uid=link_table.uid, tag_names=tags)
# audit
self.add_audit_instance_to_context(link_table, old_link_table)
return link_table

def perform_request(self, validated_request_data):
Expand All @@ -914,13 +938,21 @@ def perform_request(self, validated_request_data):
# 如果有策略使用了该联表则不能删除
if Strategy.objects.filter(strategy_type=StrategyType.RULE, link_table_uid=uid).exists():
raise LinkTableHasStrategy()
link_table = LinkTable.last_version_link_table(uid=uid)
if not link_table:
raise Http404(gettext("LinkTable not found: %s") % uid)
# audit
self.add_audit_instance_to_context(link_table)
# 删除联表
LinkTableTag.objects.filter(link_table_uid=uid).delete()
LinkTable.objects.filter(uid=uid).delete()


class ListLinkTable(LinkTableBase):
name = gettext_lazy("查询联表列表")
RequestSerializer = ListLinkTableRequestSerializer
ResponseSerializer = ListLinkTableResponseSerializer
many_response_data = True
bind_request = True

def perform_request(self, validated_request_data):
Expand Down Expand Up @@ -949,20 +981,29 @@ def perform_request(self, validated_request_data):
for t in all_tags:
tag_map[t.link_table_uid].append(t.tag_id)
# 填充关联的策略数
strategies = {
strategies = Strategy.objects.filter(strategy_type=StrategyType.RULE, link_table_uid__in=link_table_uids)
strategy_cnt_map = {
strategy["link_table_uid"]: strategy["count"]
for strategy in Strategy.objects.filter(strategy_type=StrategyType.RULE, link_table_uid__in=link_table_uids)
.values("link_table_uid")
.annotate(count=Count("link_table_uid"))
.order_by()
for strategy in strategies.values("link_table_uid").annotate(count=Count("link_table_uid")).order_by()
}
# 填充关联的最小联表版本
strategy_version_map = {
strategy["link_table_uid"]: strategy["version"]
for strategy in strategies.values("link_table_uid").annotate(version=Min("link_table_version")).order_by()
}
for link_table in link_tables:
# 填充关联的策略数
setattr(link_table, "strategy_count", strategies.get(link_table.uid, 0))
setattr(link_table, "strategy_count", strategy_cnt_map.get(link_table.uid, 0))
# 填充标签
setattr(link_table, "tags", tag_map.get(link_table.uid, []))
# 填充是否存在需要更新的策略
setattr(
link_table,
"need_update_strategy",
strategy_version_map.get(link_table.uid, link_table.version) < link_table.version,
)
# 响应
return page.get_paginated_response(data=ListLinkTableResponseSerializer(instance=link_tables, many=True).data)
return link_tables


class ListLinkTableAll(LinkTableBase):
Expand Down
Loading
Loading