fix(cma): 隔离扫尾 — kpi_alert_higher_better 拆账套 + tenant/switch 审计收口
ci/woodpecker/push/main Pipeline was canceled

任务 dama-entity-isolation-sweep-20260923(DAMA 独立回查漏项 / 任总 2026-09-23「按照建议执行」)

① 补漏同源全局键 kpi_alert_higher_better(system_configs,零 DDL)
   - deviation_engine: 新增 higher_better_key(entity_id);get_higher_better_codes(db, entity_id)
     改为只读本账套键、不回退旧全局键;未配置 → DEFAULT_HIGHER_BETTER(兜底,与原行为逐字一致)
   - budget.py: GET/PUT /alert-direction 挂 get_entity_id,只读写会话账套键;body entity_id 不信
   - scripts/migrate_higher_better_key_entity_20260923.py: --check/--apply/--down + 库名保护 + 幂等
   - 生产实况:库内该键 0 行 ⇒ 无原值可搬运(--apply 走 skip 零写入),e1 行为不变

② kpi_visibility 口径裁定:角色级天然全局 = 非账套维度,不拆(关闭本项)
   - auth_middleware 注释 + docstring 登记「有意不做账套后缀」;口径字典
     docs/global-config-keys-caliber-20260923.md(含 budget_mode/budget_driver_mode 评估结论)

③ tenant/switch 审计收口
   - detail 显式 from_entity_id → to_entity_id + source + operator{id,username,name,role}
   - 审计失败不静默:同事务回滚 + AUDIT_WRITE_FAILED ERROR + HTTP 500(不留「改了但没审计」)
   - GET /current 无写路径不落审计;历史缺口不补写

证据:新增/改写用例 17 条;全量 1397 passed(去新增文件 1380 + 17);RED 态 8 failed
This commit is contained in:
wecom-fullstack
2026-09-23 18:29:52 +08:00
parent d13bf1b6e4
commit 477515c453
10 changed files with 965 additions and 33 deletions
+28 -5
View File
@@ -32,10 +32,32 @@ DEFAULT_HIGHER_BETTER = [
CONFIG_KEY_HIGHER_BETTER = "kpi_alert_higher_better"
def get_higher_better_codes(db, entity_id: int = None) -> list:
"""读取越高越好型KPI编码列表(system_configs 可维护,无配置回落默认)"""
def higher_better_key(entity_id: int) -> str:
"""账套维度的方向配置键名:`kpi_alert_higher_better.<entity_id>`(零 DDL)
entity_id 必传:`None` → ValueError(防「漏传 → 落默认账套」重演污染)。
"""
if entity_id is None:
raise ValueError(
"higher_better_key 必须传 entity_id(账套隔离,2026-09-23 "
"dama-entity-isolation-sweep-20260923)"
)
return f"{CONFIG_KEY_HIGHER_BETTER}.{int(entity_id)}"
def get_higher_better_codes(db, entity_id: int) -> list:
"""读取**本账套**越高越好型KPI编码列表(entity_id 必传,漏传 TypeError)
账套隔离(2026-09-23 dama-entity-isolation-sweep-20260923 §一①,零 DDL):
· 只读 `kpi_alert_higher_better.<entity_id>`,**不做「回退旧全局键」**——
回退分支本身就是跨账套借用通路(与 `cash.current_balance` 同源缺陷)。
· 本账套未配置 → `DEFAULT_HIGHER_BETTER`(业务兜底:方向判定的内置默认表;
与拆键前「全局键无行」时的行为逐字一致,故对现存账套零行为差异)。
· 旧全局键 `kpi_alert_higher_better` 原样保留作回退杠杆
(搬运脚本 `--down` 只删新键,回退老码即可继续读旧键)。
"""
cfg = db.query(SystemConfig).filter(
SystemConfig.config_key == CONFIG_KEY_HIGHER_BETTER
SystemConfig.config_key == higher_better_key(entity_id)
).first()
if cfg and cfg.config_value:
try:
@@ -43,7 +65,7 @@ def get_higher_better_codes(db, entity_id: int = None) -> list:
if isinstance(codes, list):
return [str(c) for c in codes]
except Exception:
logger.warning("system_configs[%s] 解析失败, 回落默认", CONFIG_KEY_HIGHER_BETTER)
logger.warning("system_configs[%s] 解析失败, 回落默认", higher_better_key(entity_id))
return list(DEFAULT_HIGHER_BETTER)
@@ -301,7 +323,8 @@ def build_deviation_alert(db, kpi, period: str, entity_id: int = 1, min_rate: fl
actual = deviation.get("actual_value")
budget = deviation.get("budget_value")
# 方向性:越高越好型(配置化,system_configs.kpi_alert_higher_better)
# 方向性:越高越好型(配置化,本账套键 system_configs.kpi_alert_higher_better.<entity_id>;
# 2026-09-23 拆账套:entity_id 由调用方必传,不再读全局唯一键)
higher_better = kpi.kpi_code in get_higher_better_codes(db, entity_id)
if higher_better: