feat: Go后端LDAP真实对接 — AES-256-GCM密码加解密 + 登录LDAP fallback
- 新增 crypto.go: AES-256-GCM 加解密,与 Python backend 兼容 - auth.go: Login 添加 LDAP fallback(本地优先→LDAP绑定→自动创建本地用户) - ldap.go: 实现真实 LDAP 连接/用户搜索/密码验证/OU列表/用户列表 - 所有 LDAP 操作解密 admin_password 后使用 - 新增/更新密码存储时加密 - router.go: 补充 delete-user 路由 - 添加 go-ldap/v3 依赖
This commit is contained in:
1 parent
622923821b
commit
88e5f4e7ee
71 files changed
+20390
-64
No files matched your search
@@ -0,0 +1,189 @@
|
||||
"""Phase 2 影响分析测试 — EXPLAIN预检 + 部分失败策略 + 上下文感知规则。"""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import MagicMock, AsyncMock, patch
|
||||
|
||||
|
||||
# ===== EXPLAIN 预检: 表名提取 =====
|
||||
|
||||
class TestExtractTableNames:
|
||||
"""SQL 表名提取测试。"""
|
||||
|
||||
def test_update_table(self):
|
||||
from app.services.explain_preview import _extract_table_names
|
||||
assert "users" in _extract_table_names("UPDATE users SET x=1")
|
||||
|
||||
def test_delete_from_table(self):
|
||||
from app.services.explain_preview import _extract_table_names
|
||||
assert "users" in _extract_table_names("DELETE FROM users WHERE id=1")
|
||||
|
||||
def test_alter_table(self):
|
||||
from app.services.explain_preview import _extract_table_names
|
||||
assert "orders" in _extract_table_names("ALTER TABLE orders ADD COLUMN price DECIMAL")
|
||||
|
||||
def test_drop_table(self):
|
||||
from app.services.explain_preview import _extract_table_names
|
||||
assert "temp" in _extract_table_names("DROP TABLE temp")
|
||||
|
||||
def test_drop_table_if_exists(self):
|
||||
from app.services.explain_preview import _extract_table_names
|
||||
assert "temp" in _extract_table_names("DROP TABLE IF EXISTS temp")
|
||||
|
||||
def test_insert_into(self):
|
||||
from app.services.explain_preview import _extract_table_names
|
||||
assert "logs" in _extract_table_names("INSERT INTO logs (msg) VALUES ('hi')")
|
||||
|
||||
def test_select_from(self):
|
||||
from app.services.explain_preview import _extract_table_names
|
||||
names = _extract_table_names("SELECT * FROM users WHERE id=1")
|
||||
assert "users" in names
|
||||
|
||||
def test_join_tables(self):
|
||||
from app.services.explain_preview import _extract_table_names
|
||||
names = _extract_table_names("SELECT * FROM users JOIN orders ON users.id = orders.user_id")
|
||||
assert "users" in names
|
||||
assert "orders" in names
|
||||
|
||||
def test_create_table(self):
|
||||
from app.services.explain_preview import _extract_table_names
|
||||
assert "new_table" in _extract_table_names("CREATE TABLE new_table (id INT)")
|
||||
|
||||
def test_create_table_if_not_exists(self):
|
||||
from app.services.explain_preview import _extract_table_names
|
||||
assert "new_table" in _extract_table_names("CREATE TABLE IF NOT EXISTS new_table (id INT)")
|
||||
|
||||
def test_deduplication(self):
|
||||
from app.services.explain_preview import _extract_table_names
|
||||
names = _extract_table_names("SELECT * FROM users JOIN users AS u2 ON users.id = u2.id")
|
||||
assert names.count("users") == 1
|
||||
|
||||
def test_empty_sql(self):
|
||||
from app.services.explain_preview import _extract_table_names
|
||||
assert _extract_table_names("") == []
|
||||
|
||||
|
||||
# ===== ExplainResult 测试 =====
|
||||
|
||||
class TestExplainResult:
|
||||
"""EXPLAIN 结果数据结构测试。"""
|
||||
|
||||
def test_to_dict(self):
|
||||
from app.services.explain_preview import ExplainResult
|
||||
r = ExplainResult(
|
||||
sql="SELECT * FROM users",
|
||||
sql_type="DQL",
|
||||
estimated_rows=1000,
|
||||
full_table_scan=True,
|
||||
warnings=["Using filesort"],
|
||||
)
|
||||
d = r.to_dict()
|
||||
assert d["sql_type"] == "DQL"
|
||||
assert d["estimated_rows"] == 1000
|
||||
assert d["full_table_scan"] is True
|
||||
assert "Using filesort" in d["warnings"]
|
||||
|
||||
def test_error_field(self):
|
||||
from app.services.explain_preview import ExplainResult
|
||||
r = ExplainResult(error="Connection refused")
|
||||
d = r.to_dict()
|
||||
assert d["error"] == "Connection refused"
|
||||
|
||||
|
||||
# ===== 执行策略测试 =====
|
||||
|
||||
class TestExecStrategy:
|
||||
"""部分失败策略测试。"""
|
||||
|
||||
def test_schema_default_strategy(self):
|
||||
"""TicketCreate schema 默认策略是 stop_on_error。"""
|
||||
from app.schemas.ticket import TicketCreate
|
||||
data = TicketCreate(
|
||||
title="测试工单12345",
|
||||
db_type="mysql",
|
||||
instance_id=1,
|
||||
target_database="test_db",
|
||||
sql_content="SELECT 1",
|
||||
reason="测试原因abcde",
|
||||
)
|
||||
assert data.exec_strategy == "stop_on_error"
|
||||
|
||||
def test_schema_continue_strategy(self):
|
||||
from app.schemas.ticket import TicketCreate
|
||||
data = TicketCreate(
|
||||
title="测试工单12345",
|
||||
db_type="mysql",
|
||||
instance_id=1,
|
||||
target_database="test_db",
|
||||
sql_content="SELECT 1",
|
||||
reason="测试原因abcde",
|
||||
exec_strategy="continue",
|
||||
)
|
||||
assert data.exec_strategy == "continue"
|
||||
|
||||
def test_schema_transaction_strategy(self):
|
||||
from app.schemas.ticket import TicketCreate
|
||||
data = TicketCreate(
|
||||
title="测试工单12345",
|
||||
db_type="mysql",
|
||||
instance_id=1,
|
||||
target_database="test_db",
|
||||
sql_content="SELECT 1",
|
||||
reason="测试原因abcde",
|
||||
exec_strategy="transaction",
|
||||
)
|
||||
assert data.exec_strategy == "transaction"
|
||||
|
||||
|
||||
# ===== 上下文感知规则测试 =====
|
||||
|
||||
class TestRiskEvaluatorTableSizes:
|
||||
"""risk_evaluator 大表检测测试(合并自原 CTX-001)。"""
|
||||
|
||||
def test_alter_large_table_upgraded_to_high(self):
|
||||
"""大表 ALTER 升级为 high。"""
|
||||
from app.services.risk_evaluator import evaluate_risk_level
|
||||
level = evaluate_risk_level(
|
||||
"ALTER TABLE big_table ADD COLUMN status INT",
|
||||
db_type="mysql",
|
||||
table_sizes={"big_table": 500000},
|
||||
)
|
||||
assert level == "high"
|
||||
|
||||
def test_alter_small_table_not_upgraded(self):
|
||||
"""小表 ALTER 保持 medium。"""
|
||||
from app.services.risk_evaluator import evaluate_risk_level
|
||||
level = evaluate_risk_level(
|
||||
"ALTER TABLE users ADD COLUMN age INT",
|
||||
db_type="mysql",
|
||||
table_sizes={"users": 100},
|
||||
)
|
||||
assert level == "medium"
|
||||
|
||||
def test_update_large_table_upgraded_to_high(self):
|
||||
"""大表 UPDATE 无 WHERE 升级为 high。"""
|
||||
from app.services.risk_evaluator import evaluate_risk_level
|
||||
level = evaluate_risk_level(
|
||||
"UPDATE big_table SET status = 1",
|
||||
db_type="mysql",
|
||||
table_sizes={"big_table": 200000},
|
||||
)
|
||||
assert level == "high"
|
||||
|
||||
def test_no_table_sizes_no_upgrade(self):
|
||||
"""无 table_sizes 时不升级。"""
|
||||
from app.services.risk_evaluator import evaluate_risk_level
|
||||
level = evaluate_risk_level(
|
||||
"ALTER TABLE users ADD COLUMN age INT",
|
||||
db_type="mysql",
|
||||
)
|
||||
assert level == "medium"
|
||||
|
||||
def test_select_large_table_stays_low(self):
|
||||
"""SELECT 大表不升级。"""
|
||||
from app.services.risk_evaluator import evaluate_risk_level
|
||||
level = evaluate_risk_level(
|
||||
"SELECT * FROM big_table",
|
||||
db_type="mysql",
|
||||
table_sizes={"big_table": 500000},
|
||||
)
|
||||
assert level == "low"
|
||||
Reference in new issue
Block a user