ASK-20260924-15/17: Bot 通道缺省账套→400 + 差异/趋势入口期间口径回落
- deps.get_entity_id: Bot 通道(带 X-BOT-KEY)无显式账套 → 400(旧为兜底 entity 1=酣客); 无 key 的存量公开/用户端点行为不变(仍 401/兜底 1) - 新增 deps.require_bot_entity_id():写端点缺省账套一处收口 → 400(406/422 同族) 接入 bot_bridge(×2) / bot_bridge_v2 / bot_suggestions / cash_vouchers_json,并同步文档口径 - deviation_engine.run_deviation_check: period=None 不再硬编码当月,逐 KPI 回落 「该 KPI 自己的最近可用期间」(裁定2b,单一实现收口到 alert_entity_scope);(当月无 kpi_values ⇒ 差异/趋势入口永久 0 新增);R2/R3 窗口判定改为逐 KPI;显式 period 语义不变 - alert_generator.resolve_latest_period 委托同一实现(消除期间口径两份) - 测试:新增 tests/test_ask15_17_engine_and_entity_required_20260925.py(12 例); 4 个既有测试文件把「旧兜底账套 1」显式化(断言未改)
This commit is contained in:
+55
-2
@@ -1,4 +1,6 @@
|
||||
"""多租户公共依赖 — 账套模式:token优先,query/header降级为Bot服务白名单"""
|
||||
import logging
|
||||
|
||||
from fastapi import Request, Header, Query, Depends, HTTPException
|
||||
from typing import Optional
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -7,6 +9,8 @@ from app.database import get_db
|
||||
from app.auth_middleware import get_token_entity_id
|
||||
from app.models import Entity
|
||||
|
||||
logger = logging.getLogger("cma.deps")
|
||||
|
||||
|
||||
def get_entity_id(
|
||||
request: Request,
|
||||
@@ -20,7 +24,8 @@ def get_entity_id(
|
||||
1. Authorization Bearer token → 优先返回 token.entity_id(唯一可信来源)
|
||||
2. query参数 / X-Entity-Id header → 仅Bot服务通道使用(校验entity状态active)
|
||||
3. body中的 entity_id(POST场景)→ Bot服务通道兼容
|
||||
4. 兜底默认 1(酣客)
|
||||
4. **Bot 通道(带 X-BOT-KEY)无任何显式账套 → 400 显式报错**;
|
||||
无 X-BOT-KEY 的存量公开接口 → 兜底默认 1(酣客)
|
||||
|
||||
安全说明:登录用户必须通过token绑定账套,query/header传入的entity_id
|
||||
在token存在时被忽略,防止越权传参(旧漏洞:query优先且无授权校验)。
|
||||
@@ -65,7 +70,23 @@ def get_entity_id(
|
||||
# Bot通道校验不通过:不返回默认,直接拒绝(防越权注入无效entity)
|
||||
raise HTTPException(403, f"企业 entity_id={candidate} 不存在或未激活")
|
||||
|
||||
return 1 # 默认酣客(无token、无参数时兜底,兼容存量公开接口)
|
||||
# 4. 兜底(ASK-20260924-17,任总 2026-09-24 16:40「放行 17」):
|
||||
# **Bot 通道缺省账套 = 报错,不再静默兜底 entity 1(酣客)**。
|
||||
# 背景:Bot 取数接口不带账套参数时兜底 entity 1 ⇒ 跨 Bot/脚本漏传参数即用酣客数字
|
||||
# 回答博海的问题(实测:不带参数 GET /api/cma/bot/overview → {"entity_id":1, "kpis_total":44})。
|
||||
# 「问错账套」比看不到更危险,故 Bot 通道(带 X-BOT-KEY)要求**显式传账套**。
|
||||
# 边界:无 X-BOT-KEY 的存量公开/历史接口保持原兜底行为(不在 ASK-17 范围)。
|
||||
if str(request.headers.get("X-BOT-KEY") or "").strip():
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=(
|
||||
"缺少账套参数 entity_id:Bot 通道必须显式传账套"
|
||||
"(query `?entity_id=<n>` 或 header `X-Entity-Id: <n>`;"
|
||||
"1=陕西酣客、2=陕西博海),不再兜底默认账套(ASK-20260924-17)。"
|
||||
),
|
||||
)
|
||||
|
||||
return 1 # 无 token / 无参数的存量公开接口:保持原兜底(酣客)
|
||||
|
||||
|
||||
def resolve_entity_for_request(request: Request, fallback: int = 1) -> int:
|
||||
@@ -81,6 +102,38 @@ def resolve_entity_for_request(request: Request, fallback: int = 1) -> int:
|
||||
return fallback
|
||||
|
||||
|
||||
def require_bot_entity_id(data: Optional[dict], *, source: str = "") -> int:
|
||||
"""Bot 通道写端点:**账套参数必填**(ASK-20260924-17,任总 2026-09-24 16:40「放行 17」)
|
||||
|
||||
`deps.get_entity_id` 只能覆盖「用 Depends 取账套」的 GET 端点;Bot 写端点多从
|
||||
body 里读 `entity_id`,原写法 `int(data.get("entity_id") or 1)` 会**静默兜底账套 1
|
||||
(酣客)**——跨 Bot/脚本漏传参数即「用酣客数字回答博海的问题」。
|
||||
|
||||
本函数把「缺省即报错」收口到一处(`_require_*` 三处 + 建议通道 + 凭证导入共用):
|
||||
· 显式传 `entity_id`(int 或数字字符串,含 0/负数由调用方各自的 active 校验接手)→ 返回 int;
|
||||
· 缺失 / 空串 → **HTTP 400**,文案说明必须显式传账套及可选值;
|
||||
· 非数字 → HTTP 422(与既有 `entity_id 无效` 文案同族,不静默回落)。
|
||||
|
||||
`source` 仅用于日志定位(哪条写入通道漏传)。
|
||||
"""
|
||||
raw = (data or {}).get("entity_id")
|
||||
if raw is None or (isinstance(raw, str) and not raw.strip()):
|
||||
logger.warning(
|
||||
"Bot 通道缺少账套参数 entity_id → 400(source=%s)", source or "-")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=(
|
||||
"缺少账套参数 entity_id:Bot 通道必须显式传账套"
|
||||
"(body.entity_id / header `X-Entity-Id`;1=陕西酣客、2=陕西博海),"
|
||||
"不再兜底默认账套(ASK-20260924-17)。"
|
||||
),
|
||||
)
|
||||
try:
|
||||
return int(raw)
|
||||
except (TypeError, ValueError):
|
||||
raise HTTPException(422, f"entity_id 无效: {raw!r}")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 跨租户读取防护(cma-cross-entity-endpoints-auth-20260914 补单)
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user