feat: Phase1安全基线 — 风险等级+审核超时+执行进度+通知脱敏+高危确认+维护窗口 (1119测试)
新增功能:
- ticket_sql_items模型: 逐条SQL执行记录(状态/耗时/影响行数)
- risk_evaluator.py: 4级风险评估(low/medium/high/critical), 支持MySQL/PG/Redis/Mongo
- Ticket模型: 新增risk_level + workflow_id字段
- 审核引擎签名改造: audit(sql, db_type, instance_id=None) 支持EXPLAIN预检
- 审核超时保护: 10s超时跳过审核, 防止工单创建阻塞
- 工单创建自动风险计算 + 审批流匹配(instance.workflow_id优先)
- SQL items查询API: GET /{ticket_id}/sql-items 含进度统计
- 执行器集成: 执行完成后自动更新SQL items逐条状态
- 通知脱敏: password/secret/token自动掩码, SQL预览截断100字符
- 高危操作强制二次确认: high/critical级别需confirmed=true
- 维护窗口控制: system_settings配置执行时间窗口(支持跨午夜)
- 45个新测试: 风险评估24+通知脱敏5+维护窗口2+SQL分类11+配置2
This commit is contained in:
1 parent
030f3f2339
commit
7be0bf1a7c
9 files changed
+809
-16
No files matched your search
@@ -15,6 +15,37 @@ from urllib.parse import quote
|
||||
class NotificationSender:
|
||||
"""通知发送器,支持钉钉、飞书、邮件。"""
|
||||
|
||||
# 敏感字段关键词(用于通知脱敏)
|
||||
_SENSITIVE_PATTERNS = [
|
||||
(r"password\s*=\s*'[^']*'", "password='***'"),
|
||||
(r"password\s*=\s*\"[^\"]*\"", 'password="***"'),
|
||||
(r"secret\s*=\s*'[^']*'", "secret='***'"),
|
||||
(r"token\s*=\s*'[^']*'", "token='***'"),
|
||||
(r"DROP\s+TABLE\s+\w+", "DROP TABLE ***"),
|
||||
(r"TRUNCATE\s+TABLE?\s*\w+", "TRUNCATE ***"),
|
||||
(r"FLUSHALL", "FLUSHALL"),
|
||||
(r"FLUSHDB", "FLUSHDB"),
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def _mask_sensitive_data(data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""对通知数据中的敏感字段进行脱敏。"""
|
||||
import re
|
||||
masked = dict(data)
|
||||
# sql_preview 截断到前100字符 + 脱敏
|
||||
if "sql_preview" in masked and masked["sql_preview"]:
|
||||
preview = str(masked["sql_preview"])[:100]
|
||||
for pattern, replacement in NotificationSender._SENSITIVE_PATTERNS:
|
||||
preview = re.sub(pattern, replacement, preview, flags=re.IGNORECASE)
|
||||
masked["sql_preview"] = preview + ("..." if len(str(data.get("sql_preview", ""))) > 100 else "")
|
||||
# error 字段脱敏
|
||||
if "error" in masked and masked["error"]:
|
||||
err = str(masked["error"])[:200]
|
||||
for pattern, replacement in NotificationSender._SENSITIVE_PATTERNS:
|
||||
err = re.sub(pattern, replacement, err, flags=re.IGNORECASE)
|
||||
masked["error"] = err
|
||||
return masked
|
||||
|
||||
# 内置消息模板
|
||||
TEMPLATES = {
|
||||
"ticket_created": {
|
||||
@@ -91,6 +122,9 @@ class NotificationSender:
|
||||
event_type: 事件类型
|
||||
data: 模板数据
|
||||
"""
|
||||
# 通知脱敏:隐藏 SQL 中的敏感内容
|
||||
data = self._mask_sensitive_data(data)
|
||||
|
||||
try:
|
||||
if channel_type == "dingtalk":
|
||||
return await self._send_dingtalk(config, event_type, data)
|
||||
|
||||
Reference in new issue
Block a user