feat: Phase2影响分析 — EXPLAIN预检+大表检测(简化版)+执行策略+风险评估table_sizes支持 (1141测试)
新增: - explain_preview.py: EXPLAIN预检服务(MySQL/PG), 影响行数预估, 全表扫描检测 - ticket.executor: 三种执行策略(stop_on_error/continue/transaction) - risk_evaluator: table_sizes参数, 大表ALTER/UPDATE/DELETE自动升级high - test_phase2_features.py: 22个测试(EXPLAIN+执行策略+大表检测) 简化: - 砍掉CTX-001上下文感知规则(复杂二次扫描), 合并大表检测到risk_evaluator - 审核引擎保持纯静态分析, 不再导入_RULE_REGISTRY做二次扫描 模型: - Ticket加exec_strategy字段 - TicketSqlItem模型 - schema加sql_type/exec_strategy/risk_level/workflow_id
This commit is contained in:
1 parent
7be0bf1a7c
commit
f6f9142ce8
7 files changed
+574
-22
No files matched your search
@@ -498,10 +498,25 @@ async def create_ticket(
|
||||
# 3. 验证工单内容安全性
|
||||
_validate_ticket_content(data)
|
||||
|
||||
# 3.5 EXPLAIN 预检(大表检测合并到 risk_evaluator,不再单独查表大小)
|
||||
table_sizes = {}
|
||||
explain_warnings = []
|
||||
try:
|
||||
from app.services.explain_preview import run_explain_preview
|
||||
import asyncio as _asyncio
|
||||
explain_result = await _asyncio.wait_for(
|
||||
run_explain_preview(data.sql_content, instance, data.target_database),
|
||||
timeout=8.0,
|
||||
)
|
||||
explain_warnings = explain_result.warnings
|
||||
table_sizes = explain_result.table_sizes or {}
|
||||
except Exception as e:
|
||||
import asyncio as _asyncio
|
||||
logger.warning("EXPLAIN 预检失败(非致命): %s", e)
|
||||
|
||||
# 4. 自动审核 SQL(带超时保护)
|
||||
env = "production" if instance.env == "production" else "development"
|
||||
v2_engine = SQLAuditEngineV2(db_session=db, env=env)
|
||||
import asyncio as _asyncio
|
||||
try:
|
||||
v2_report = await _asyncio.wait_for(
|
||||
v2_engine.audit(data.sql_content, db_type=data.db_type, instance_id=data.instance_id),
|
||||
@@ -525,8 +540,13 @@ async def create_ticket(
|
||||
sql_type=data.sql_type or "",
|
||||
audit_findings=audit_findings_raw,
|
||||
statement_count=len(stmt_list),
|
||||
table_sizes=table_sizes,
|
||||
)
|
||||
|
||||
# EXPLAIN 结果可能升级风险等级
|
||||
if explain_warnings and risk_level == "low":
|
||||
risk_level = "medium"
|
||||
|
||||
# 6. 匹配审批流 — 优先按 instance.workflow_id,其次按 risk_level 匹配默认流
|
||||
workflow = None
|
||||
if instance.workflow_id:
|
||||
@@ -560,6 +580,7 @@ async def create_ticket(
|
||||
priority=data.priority,
|
||||
risk_level=risk_level,
|
||||
workflow_id=workflow.id if workflow else None,
|
||||
exec_strategy=data.exec_strategy or "stop_on_error",
|
||||
applicant_id=current_user.id,
|
||||
status=initial_status,
|
||||
audit_result=json.dumps(v2_report.to_dict(), ensure_ascii=False) if v2_report and v2_report.findings else None,
|
||||
|
||||
Reference in new issue
Block a user