From afc96c667a11e40214b64206e96e976bdd77127b Mon Sep 17 00:00:00 2001 From: zzr <103238445+wswsadadbaba123@users.noreply.github.com> Date: Mon, 19 Oct 2026 11:51:38 +0800 Subject: [PATCH] docs(feishu): explain CA trust troubleshooting for TLS failures (#6869) * docs(feishu): explain CA trust troubleshooting for TLS failures * docs(feishu): sync Chinese TLS and notification pointers --- README.md | 2 + README_zh.md | 4 ++ backend/docs/IM_CHANNEL_CONNECTIONS.md | 64 ++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/README.md b/README.md index bb78f03d3a..f0fea9898b 100644 --- a/README.md +++ b/README.md @@ -1185,6 +1185,8 @@ DINGTALK_CLIENT_SECRET=your_client_secret 5. The bot supports inbound text, image, and file messages. Inbound attachment downloads are limited to 20 MB per attachment. 6. _(Optional)_ Interactive clarification cards: set `card_interaction_enabled: true` under `channels.feishu` to let the agent's option-based clarifications render as clickable button cards, preserving any background context before the question. Then, in the developer console, open **Callback Configuration** (回调配置 — a separate tab from **Event Subscriptions**), subscribe to `card.action.trigger` in **Long Connection** mode, and publish a new app version. A click resolves the clarification exactly like typing the choice; only the user who triggered the clarification can operate its card. Button answers are saved in the conversation history, and subsequent clarifications continue in the same thread. +If the SDK repeatedly logs `CERTIFICATE_VERIFY_FAILED`, see [Feishu / Lark TLS troubleshooting](backend/docs/IM_CHANNEL_CONNECTIONS.md#feishu--lark-tls-troubleshooting) to check the Gateway's CA trust configuration. + Scheduled-task result and lifecycle notices can also be pushed to a bound Feishu/Lark user, without a new inbound message. They use the same notification outbox and localized summaries as WeCom. The app must be able to send to that user; see [Feishu scheduled-task notifications](backend/docs/IM_CHANNEL_CONNECTIONS.md#feishu-scheduled-task-notifications). **WeChat Setup** diff --git a/README_zh.md b/README_zh.md index d64a80a274..2a479bd707 100644 --- a/README_zh.md +++ b/README_zh.md @@ -572,6 +572,10 @@ DINGTALK_CLIENT_SECRET=your_client_secret 4. 复制 App ID 和 App Secret,在 `.env` 中设置 `FEISHU_APP_ID` 和 `FEISHU_APP_SECRET`,并在 `config.yaml` 中启用该渠道。 5. _(可选)_ 交互式澄清卡片:在 `channels.feishu` 下设置 `card_interaction_enabled: true`,让 agent 的选项式提问渲染为可点击的按钮卡片,并在问题前保留背景说明。随后在开发者后台打开 **回调配置**(与「事件订阅」是不同的标签页),订阅 `card.action.trigger` 并选择 **长连接**,最后发布新版本。点击按钮等同于输入该选项作答;只有触发该次提问的用户才能操作对应卡片。按钮答案会保存到对话历史中,后续澄清继续在同一会话内进行。 +如果 SDK 反复记录 `CERTIFICATE_VERIFY_FAILED`,参见 [Feishu / Lark TLS 故障排查](backend/docs/IM_CHANNEL_CONNECTIONS.md#feishu--lark-tls-troubleshooting),检查 Gateway 的 CA 信任配置。 + +定时任务的执行结果和生命周期通知也可以主动推送给已绑定的飞书/Lark 用户,无需用户先发送新消息。它们与企业微信共用通知发件箱和本地化摘要机制。应用必须具备向该用户发送消息的权限,参见[飞书定时任务通知](backend/docs/IM_CHANNEL_CONNECTIONS.md#feishu-scheduled-task-notifications)。 + **WeChat 配置** 1. 在 `config.yaml` 中启用 `wechat` 渠道。 diff --git a/backend/docs/IM_CHANNEL_CONNECTIONS.md b/backend/docs/IM_CHANNEL_CONNECTIONS.md index e15ce9b4e5..6e26dd1e59 100644 --- a/backend/docs/IM_CHANNEL_CONNECTIONS.md +++ b/backend/docs/IM_CHANNEL_CONNECTIONS.md @@ -448,6 +448,70 @@ Neither can make anything be *acted on*. The `allowed_users` allowlist and per-e **Bound identity:** once a pubkey completes `/connect`, its inbound messages resolve to that connection and run under the bound DeerFlow user (memory, files, and artifacts land in that user's buckets). Bindings are scoped to the relay host, so the same pubkey on a different relay is a different identity and must bind separately. +### Feishu / Lark TLS troubleshooting + +If Gateway startup succeeds but the Lark SDK keeps logging +`connect failed, err: [SSL: CERTIFICATE_VERIFY_FAILED] ... self-signed certificate in certificate chain`, +the channel worker has started but its connection has not passed TLS verification. +Changing the App ID, App Secret, or event permissions does not repair a certificate +trust failure. A browser that can reach Feishu does not prove that the Gateway's +Python environment trusts the same CA certificates. + +The SDK first obtains a connection URL over HTTPS using Requests, then opens a +WebSocket using Python's default SSL context. Check both trust sources in the +**same environment and process configuration as the Gateway**. From the repository +root, after installing backend dependencies: + +```bash +uv run --no-sync --project backend python -c "import ssl; print(ssl.get_default_verify_paths()); print(ssl.create_default_context().cert_store_stats())" +uv run --no-sync --project backend python -c "import requests; print(requests.certs.where()); print(requests.Session().merge_environment_settings('https://open.feishu.cn', {}, None, None, None)['verify'])" +``` + +These commands inspect trust configuration without sending app credentials or +connecting to Feishu. They do not establish that the remote certificate chain +is valid. Run them inside the Gateway container when using Docker; host Python +and the container can have different trust stores. + +If a corporate proxy or security product inspects TLS, ask its administrator for +the approved root/intermediate CA certificates in PEM format and verify their +provenance. Use a CA bundle that retains the public roots needed by other Gateway +connections and includes those approved certificates. If no TLS inspection is +expected, investigate the presented certificate chain and repair the Python or +container CA installation before adding any certificate to trust. + +Set **both** variables to the absolute path of that bundle in the Gateway's +environment, for example in the root `.env`: + +```dotenv +SSL_CERT_FILE=/absolute/path/to/approved-ca-bundle.pem +REQUESTS_CA_BUNDLE=/absolute/path/to/approved-ca-bundle.pem +``` + +`SSL_CERT_FILE` selects the default OpenSSL CA file for the WebSocket connection +(and clients such as HTTPX); `REQUESTS_CA_BUNDLE` selects the Requests CA bundle +for connection discovery and synchronous API calls. Setting only the Requests +variable can leave the WebSocket handshake failing. The diagnostic commands above +do not load `.env` themselves: export these variables in the diagnostic shell as +well, using your shell's environment-variable syntax. + +For Docker, mount the bundle read-only into the `gateway` service and use its +**container path** in both variables. A host path in `.env` is not automatically +mounted. Recreate the Gateway container after changing its environment or mounts; +for local development, restart the Gateway process. These variables configure +trust for the whole Gateway, so use an operator-approved bundle. + +Do not disable certificate or hostname verification (`verify=False`, +`CERT_NONE`, or an unverified SSL context) to make the bot connect. Confirm recovery +by checking that the certificate errors stop and that the bot receives and replies +to a test message; the earlier "channel started" log alone is not a handshake or +message-delivery check. If the error persists, compare the CA issuer and trust +configuration for both the configured Feishu/Lark API domain and the WebSocket +host. When sharing diagnostics, omit app secrets, tokens, and connection-URL query +parameters. + +References: [Python SSL trust paths](https://docs.python.org/3.12/library/ssl.html#ssl.get_default_verify_paths), +[Requests CA bundles](https://requests.readthedocs.io/en/latest/user/advanced/#ssl-cert-verification). + ### Feishu scheduled-task notifications Feishu/Lark sends scheduled-task result and lifecycle notices as static Markdown