fix(cma): 隔离扫尾 — kpi_alert_higher_better 拆账套 + tenant/switch 审计收口
ci/woodpecker/push/main Pipeline was canceled
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:
+24
-11
@@ -1079,17 +1079,24 @@ def get_deviation_alert_attribution(
|
||||
@router.get("/alert-direction")
|
||||
def get_alert_direction(
|
||||
db: Session = Depends(get_db),
|
||||
entity_id: int = Depends(get_entity_id),
|
||||
):
|
||||
"""越高越好型KPI方向配置 (P2-⑤ 2026-08-28: system_configs 可维护)"""
|
||||
from app.utils.deviation_engine import get_higher_better_codes, CONFIG_KEY_HIGHER_BETTER
|
||||
"""越高越好型KPI方向配置(**按会话账套**;2026-09-23 拆账套,零 DDL)
|
||||
|
||||
与 B1 `cash.current_balance` 同款:只读本账套键 `kpi_alert_higher_better.<entity_id>`,
|
||||
本账套未配置 → 走 deviation_engine 内置默认表(兜底,不跨账套借用)。
|
||||
"""
|
||||
from app.utils.deviation_engine import get_higher_better_codes, higher_better_key
|
||||
from app.models import SystemConfig
|
||||
|
||||
key = higher_better_key(entity_id)
|
||||
cfg = db.query(SystemConfig).filter(
|
||||
SystemConfig.config_key == CONFIG_KEY_HIGHER_BETTER
|
||||
SystemConfig.config_key == key
|
||||
).first()
|
||||
codes = get_higher_better_codes(db)
|
||||
codes = get_higher_better_codes(db, entity_id)
|
||||
return {
|
||||
"config_key": CONFIG_KEY_HIGHER_BETTER,
|
||||
"config_key": key,
|
||||
"entity_id": entity_id,
|
||||
"codes": codes,
|
||||
"is_configured": bool(cfg and cfg.config_value),
|
||||
}
|
||||
@@ -1100,10 +1107,15 @@ def update_alert_direction(
|
||||
data: dict,
|
||||
db: Session = Depends(get_db),
|
||||
current_user=Depends(require_auth),
|
||||
entity_id: int = Depends(get_entity_id),
|
||||
):
|
||||
"""维护越高越好型KPI方向配置 (P2-⑤) body: {codes: ["SALES_TOTAL", ...]}"""
|
||||
"""维护越高越好型KPI方向配置 (P2-⑤) body: {codes: ["SALES_TOTAL", ...]}
|
||||
|
||||
账套隔离(2026-09-23):只写本账套键 `kpi_alert_higher_better.<entity_id>`;
|
||||
body 里的 `entity_id` 一律不信(会话账套为准,同 B1 口径)。
|
||||
"""
|
||||
import json as _json
|
||||
from app.utils.deviation_engine import CONFIG_KEY_HIGHER_BETTER
|
||||
from app.utils.deviation_engine import higher_better_key
|
||||
from app.models import SystemConfig
|
||||
|
||||
codes = data.get("codes")
|
||||
@@ -1111,19 +1123,20 @@ def update_alert_direction(
|
||||
raise HTTPException(400, "codes 必须是非空数组")
|
||||
codes = [str(c) for c in codes]
|
||||
|
||||
key = higher_better_key(entity_id)
|
||||
cfg = db.query(SystemConfig).filter(
|
||||
SystemConfig.config_key == CONFIG_KEY_HIGHER_BETTER
|
||||
SystemConfig.config_key == key
|
||||
).first()
|
||||
if cfg:
|
||||
cfg.config_value = _json.dumps(codes, ensure_ascii=False)
|
||||
else:
|
||||
db.add(SystemConfig(
|
||||
config_key=CONFIG_KEY_HIGHER_BETTER,
|
||||
config_key=key,
|
||||
config_value=_json.dumps(codes, ensure_ascii=False),
|
||||
description="越高越好型KPI编码列表(实际低于预算才告警)",
|
||||
description=f"越高越好型KPI编码列表(实际低于预算才告警)— 账套 {int(entity_id)}",
|
||||
))
|
||||
db.commit()
|
||||
return {"success": True, "config_key": CONFIG_KEY_HIGHER_BETTER, "codes": codes}
|
||||
return {"success": True, "config_key": key, "entity_id": entity_id, "codes": codes}
|
||||
|
||||
|
||||
@router.put("/deviation-alerts/{alert_id}")
|
||||
|
||||
Reference in New Issue
Block a user