mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-09-11 06:28:58 +00:00
fix(wechat): validate timing configuration (#4280)
This commit is contained in:
parent
5994fdf38c
commit
f8bef42a04
@ -427,7 +427,10 @@ channels:
|
|||||||
ilink_bot_id: $WECHAT_ILINK_BOT_ID
|
ilink_bot_id: $WECHAT_ILINK_BOT_ID
|
||||||
qrcode_login_enabled: true # optional: allow first-time QR bootstrap when bot_token is absent
|
qrcode_login_enabled: true # optional: allow first-time QR bootstrap when bot_token is absent
|
||||||
allowed_users: [] # empty = allow all
|
allowed_users: [] # empty = allow all
|
||||||
polling_timeout: 35
|
polling_timeout: 35 # timing values must be positive finite seconds
|
||||||
|
polling_retry_delay: 5
|
||||||
|
qrcode_poll_interval: 2
|
||||||
|
qrcode_poll_timeout: 180
|
||||||
state_dir: ./.deer-flow/wechat/state
|
state_dir: ./.deer-flow/wechat/state
|
||||||
max_inbound_image_bytes: 20971520
|
max_inbound_image_bytes: 20971520
|
||||||
max_outbound_image_bytes: 20971520
|
max_outbound_image_bytes: 20971520
|
||||||
|
|||||||
@ -546,6 +546,7 @@ The cached value is reused for both the blocking (`runs.wait`) and streaming (`_
|
|||||||
- Disabled by default. It is a user-binding layer on top of the existing `channels.*` runtime config, not a replacement for provider bot credentials.
|
- Disabled by default. It is a user-binding layer on top of the existing `channels.*` runtime config, not a replacement for provider bot credentials.
|
||||||
- No public IP, OAuth callback URL, or provider webhook route is required by the current implementation.
|
- No public IP, OAuth callback URL, or provider webhook route is required by the current implementation.
|
||||||
- Telegram uses a deep-link `/start <code>` flow over the existing long-polling worker. Slack, Discord, Feishu/Lark, DingTalk, WeChat, and WeCom use `/connect <code>` over their existing outbound channel workers.
|
- Telegram uses a deep-link `/start <code>` flow over the existing long-polling worker. Slack, Discord, Feishu/Lark, DingTalk, WeChat, and WeCom use `/connect <code>` over their existing outbound channel workers.
|
||||||
|
- WeChat timing settings (`polling_timeout`, `polling_retry_delay`, `qrcode_poll_interval`, `qrcode_poll_timeout`) accept only positive finite seconds; invalid values fall back to their defaults so polling cannot enter a hot loop or sleep forever.
|
||||||
- Frontend APIs: `GET /api/channels/providers`, `GET /api/channels/connections`, `POST /api/channels/{provider}/connect`, and `DELETE /api/channels/connections/{connection_id}`.
|
- Frontend APIs: `GET /api/channels/providers`, `GET /api/channels/connections`, `POST /api/channels/{provider}/connect`, and `DELETE /api/channels/connections/{connection_id}`.
|
||||||
- Browser APIs remain protected by normal Gateway auth/CSRF. Provider messages arrive through the already-configured channel workers.
|
- Browser APIs remain protected by normal Gateway auth/CSRF. Provider messages arrive through the already-configured channel workers.
|
||||||
- Provider-level `connection_status` reflects the user's newest connection row. With no binding it is `not_connected`, except in auth-disabled local mode where a configured running channel reports `connected` because all channel messages already route to the default user.
|
- Provider-level `connection_status` reflects the user's newest connection row. With no binding it is `not_connected`, except in auth-disabled local mode where a configured running channel reports `connected` because all channel messages already route to the default user.
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import binascii
|
|||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import math
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import secrets
|
import secrets
|
||||||
import tempfile
|
import tempfile
|
||||||
@ -1456,9 +1457,10 @@ class WechatChannel(Channel):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _coerce_float(value: Any, default: float) -> float:
|
def _coerce_float(value: Any, default: float) -> float:
|
||||||
try:
|
try:
|
||||||
return float(value)
|
parsed = float(value)
|
||||||
except (TypeError, ValueError):
|
except (OverflowError, TypeError, ValueError):
|
||||||
return default
|
return default
|
||||||
|
return parsed if math.isfinite(parsed) and parsed > 0 else default
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _coerce_int(value: Any, default: int) -> int:
|
def _coerce_int(value: Any, default: int) -> int:
|
||||||
|
|||||||
@ -84,6 +84,33 @@ class _MockAsyncClient:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def test_timing_config_requires_positive_finite_values():
|
||||||
|
from app.channels.wechat import WechatChannel
|
||||||
|
|
||||||
|
timing_defaults = {
|
||||||
|
"polling_timeout": WechatChannel.DEFAULT_POLLING_TIMEOUT,
|
||||||
|
"polling_retry_delay": WechatChannel.DEFAULT_RETRY_DELAY,
|
||||||
|
"qrcode_poll_interval": WechatChannel.DEFAULT_QRCODE_POLL_INTERVAL,
|
||||||
|
"qrcode_poll_timeout": WechatChannel.DEFAULT_QRCODE_POLL_TIMEOUT,
|
||||||
|
}
|
||||||
|
attributes = {
|
||||||
|
"polling_timeout": "_polling_timeout",
|
||||||
|
"polling_retry_delay": "_retry_delay",
|
||||||
|
"qrcode_poll_interval": "_qrcode_poll_interval",
|
||||||
|
"qrcode_poll_timeout": "_qrcode_poll_timeout",
|
||||||
|
}
|
||||||
|
|
||||||
|
for invalid in (0, -1, float("nan"), float("inf"), float("-inf"), 10**1000):
|
||||||
|
channel = WechatChannel(
|
||||||
|
bus=MessageBus(),
|
||||||
|
config={"bot_token": "test-token", **dict.fromkeys(timing_defaults, invalid)},
|
||||||
|
)
|
||||||
|
assert {key: getattr(channel, attributes[key]) for key in timing_defaults} == timing_defaults
|
||||||
|
|
||||||
|
channel = WechatChannel(bus=MessageBus(), config={"bot_token": "test-token", "polling_retry_delay": "0.25"})
|
||||||
|
assert channel._retry_delay == 0.25
|
||||||
|
|
||||||
|
|
||||||
def test_handle_update_publishes_private_chat_message():
|
def test_handle_update_publishes_private_chat_message():
|
||||||
from app.channels.wechat import WechatChannel
|
from app.channels.wechat import WechatChannel
|
||||||
|
|
||||||
|
|||||||
@ -1856,11 +1856,12 @@ run_ownership:
|
|||||||
# # Optional: sent as SKRouteTag header when provided
|
# # Optional: sent as SKRouteTag header when provided
|
||||||
# route_tag: ""
|
# route_tag: ""
|
||||||
# allowed_users: [] # empty = allow all
|
# allowed_users: [] # empty = allow all
|
||||||
# # Optional: long-polling timeout in seconds
|
# # Optional: timing values must be positive finite seconds
|
||||||
# polling_timeout: 35
|
# polling_timeout: 35
|
||||||
# # Optional: QR poll interval in seconds when qrcode_login_enabled is true
|
# polling_retry_delay: 5
|
||||||
|
# # QR poll interval when qrcode_login_enabled is true
|
||||||
# qrcode_poll_interval: 2
|
# qrcode_poll_interval: 2
|
||||||
# # Optional: QR bootstrap timeout in seconds
|
# # QR bootstrap timeout
|
||||||
# qrcode_poll_timeout: 180
|
# qrcode_poll_timeout: 180
|
||||||
# # Optional: persist getupdates cursor under the gateway container volume
|
# # Optional: persist getupdates cursor under the gateway container volume
|
||||||
# state_dir: ./.deer-flow/wechat/state
|
# state_dir: ./.deer-flow/wechat/state
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user