diff --git a/apps/api/src/core/config.py b/apps/api/src/core/config.py index 111d23e0..e9446ae8 100644 --- a/apps/api/src/core/config.py +++ b/apps/api/src/core/config.py @@ -225,21 +225,24 @@ class Settings(BaseSettings): default="", description="Telegram Chat ID for notifications", ) - OPENCLAW_TG_USER_WHITELIST: list[int] = Field( - default=[], - description="Telegram user IDs allowed to sign approvals", + # 使用 str 避免 pydantic-settings 自動 JSON 解析,在 property 中轉換 + _OPENCLAW_TG_USER_WHITELIST_RAW: str = Field( + default="", + alias="OPENCLAW_TG_USER_WHITELIST", + description="Telegram user IDs allowed to sign approvals (comma-separated)", ) - @field_validator("OPENCLAW_TG_USER_WHITELIST", mode="before") - @classmethod - def parse_tg_whitelist(cls, v: str | list[int] | int) -> list[int]: - if isinstance(v, int): - return [v] - if isinstance(v, str): - if not v.strip(): - return [] - return [int(uid.strip()) for uid in v.split(",")] - return v + @property + def OPENCLAW_TG_USER_WHITELIST(self) -> list[int]: + """Parse comma-separated user IDs to list[int]""" + raw = self._OPENCLAW_TG_USER_WHITELIST_RAW + if not raw or not raw.strip(): + return [] + # Handle JSON array format or comma-separated + if raw.startswith("["): + import json + return json.loads(raw) + return [int(uid.strip()) for uid in raw.split(",")] # ========================================================================== # Phase 5: Webhook Security (CISO 要求)