github soimy/openclaw-channel-dingtalk v3.7.0

3 hours ago

v3.7.0 发布说明

本次 minor 版本带来两项面向体验与安全的能力:AI 卡片长任务进度块Gateway RPC 能力开关 / 白名单;同时完成多轮安全加固(SecretInput 环境变量读取收敛、出站媒体本机读取边界)、引用与 mention 上下文修复,以及一次全仓领域目录迁移与格式化收口。

Important

本版本抬高了最低宿主版本:插件现在依赖 OpenClaw 2026.8.1 起公开导出的 openclaw/plugin-sdk/secret-ref-readonly。宿主低于 2026.8.1 时插件会因缺少该 SDK 子路径而加载失败,请先升级 OpenClaw 宿主。

最新版本入口latest.md

⚠️ 破坏性变更

  • 最低宿主版本从 2026.7.1-2 抬升到 2026.8.1
    • PR #609(by @soimy)为隔离 clientSecretenv 引用读取,改用 OpenClaw 2026.8.1 起公开导出的 openclaw/plugin-sdk/secret-ref-readonly
    • 同步更新 peerDependencies.openclawopenclaw.compat.pluginApiopenclaw.install.minHostVersionopenclaw.build.openclawVersion 与开发依赖中的 openclaw,均为 2026.8.1
    • 连带适配 2026.8 类型面:移除宿主已删除的 ChannelGroupAdapter.resolveGroupIntroHint(core 从未消费,属死代码);历史会话扫描改为读取 canonical delivery 状态,并保留对未执行 openclaw doctor --fix 迁移的旧字段(origin / lastChannel / lastTo / lastAccountId)的运行时兼容读取,避免历史群 peer 恢复能力丢失。

✨ 功能与体验改进

1. AI 卡片长任务进度块

  • 长任务期间在同一张卡片顶部保留可替换的进度块
    • PR #612(by @soimy)让卡片在创建之后到最终答案之间的静默期(最长可达数分钟)不再"看起来卡住":进度块展示当前阶段、已完成步数与已耗时,任务超过 10 秒才出现(若已有可关联的工具调用则立即出现),之后按 30 秒心跳刷新,并在最终答案提交前清除。
    • 隐私安全:进度文本只由归一化后的工具名派生,绝不渲染命令参数、工具输出、URL、token 或凭据。
    • 所有退出路径都释放控制器ReplyStrategy 新增幂等 dispose(),入站 dispatch 在 finally 中调用,覆盖既不 finalize 也不 abort 的 ask-user 接管早退分支;修复前接管后进度定时器与事件订阅会永久存活,recall 失败时用户会看到一张永远刷新"⏳ 任务处理中"的卡片。
    • 可配置cardTaskProgresstrue 强制开启 / false 强制关闭 / 未设置默认开启,但 cardStreamingMode 显式"off" 时默认关闭);cardTaskProgressRefreshheartbeat 默认,出现时 1 次 + 每 30 秒 1 次;interval 每个可关联工具事件都推送,由 cardStreamInterval 节流)。两个字段均已写入 openclaw.plugin.json 的默认账号与 named account 两处 schema 并附 UI hint,且不注入 JSON-Schema / Zod 默认值,以保证 named account 能正确继承渠道级设置。
    • 架构边界:新增 src/platform/runtime-events.ts,把通用 runtime 事件面(类型、引用计数 fan-out、字段访问器、run correlator)从 ack-reaction/ 抽到 platform/card/ 不再依赖 ack-reaction 私有模块;fan-out 逐个隔离监听器异常。
    • 真机验证驱动的修正(宿主 OpenClaw 2026.9.2):工具事件 phase 实际为 start / update / result,计步改为匹配 result(此前匹配 "end" 导致步数恒为 0);钉钉客户端对同一 markdown block 内的多行只刷新尾行,进度块因此收敛为单行单 block。
    • 文档更新:docs/user/features/ai-card.mddocs/user/reference/api-usage-and-cost.mddocs/user/reference/configuration.md

2. Gateway RPC 能力开关与白名单

  • docs / 主动发送 RPC 可显式关闭,并支持空间与目标白名单
    • PR #611(by @soimy)新增 gatewayCapabilities 配置,回应 ClawHub 安全审核(Issue #608)对 gateway-docs-and-send-rpc 的 finding,并在用户文档中说明其信任模型与所需钉钉权限。
    • gatewayCapabilities.tools.docs / gatewayCapabilities.tools.proactiveSend:能力开关,默认 true;关闭后 dingtalk.docs.*dingtalk-connector.docs.* 别名的全部 RPC 统一拒绝,能力开关走 fast-path(先于 required 参数解析),缺参时返回结构化 deny 而非参数错误。
    • gatewayCapabilities.docs.allowedSpaceIds:文档空间白名单(未配置不限制;配置后至少一项,[] 会被 schema 直接拒绝,运行时按 fail-closed 全部拒绝)。
    • gatewayCapabilities.send.allowedTargets:发送目标白名单,每项必须为 user:* / group:*
    • 多账号按子键(tools / docs / send)与渠道级合并,账号级同子键优先,因此账号级只覆盖局部子键时渠道级限制仍然生效。
    • 拒绝日志统一 [DingTalk][GatewayRPC][Denied] 前缀,reason 为静态文案,不泄露凭证;status / probe 不受影响。
    • 文档更新:docs/user/reference/gateway-rpc.md 新增"能力开关与白名单"章节,security-policies.mdconfiguration.md 同步补充。

🛠 安全与修复

  • SecretInput 环境变量读取收敛到单个已授权变量PR #609,by @soimy

    • 不再把整个 process.env 透传给宿主 SecretInput 解析器:env 引用改为"归一化引用 → 只读路径授权(canResolveEnvSecretRefInReadOnlyPath)→ 仅读取 process.env[ref.id]",与 OpenClaw 官方频道的实现形态对齐,消除 suspicious.env_credential_access 静态指纹。
    • 未授权引用在发起任何钉钉网络请求之前本地失败,并区分"未授权"/"已授权但变量未设置或为空"/"provider source 不匹配"三类原因,避免误导排查方向;file 引用行为不变(显式传 env: {})。
    • scripts/verify-runtime-package.mjs 新增构建产物守卫:命中 env: process.env 形态即失败。
  • 出站媒体先校验本机根目录再读取PR #610,by @soimy

    • 配置 mediaLocalRoots 后,仅当媒体路径的 realpath 位于允许目录内才直接读取主机文件,越界路径统一交由受控 runtime media bridge 处理。
    • 修复符号链接绕过(realpath + 打开后二次校验、O_NOFOLLOW)、语音源文件绕过边界的外泄路径(改为先按边界取字节写入插件自有临时文件再供 ffmpeg/ffprobe 读取)、插件自有临时媒体被根目录误拦的回归,并将文件系统根 / 视为无效条目。
    • 文档新增"出站媒体主机读取边界 mediaLocalRoots"章节。
  • 引用正文从真实 repliedMsg 报文形态恢复PR #599,by @BenGuanRan

    • message-context-store 未命中时(群聊引用他人消息、超 TTL、插件安装前的消息),改为从 content.content 提取文本正文、递归提取 cardContent 中的 TEXT 节点,并保留 legacy content.text 等形态兼容,修复引用上下文丢失。
    • 文档更新:docs/user/features/message-types.md
  • 上下文保留结构化 mention IDPR #603,by @huyua9

    • message-context-store 新增 mentionUserIds,入站消息把顶层 atUsers 与 richText atUserId 合并去重后持久化;群聊 GroupSystemPrompt 增加脱敏后的 mentionedDingtalkIds
    • 明确不从文本显示名反推 ID,只保留 payload 可证实的原始钉钉 ID。

🧩 架构与工程

  • 完成领域目录迁移并全仓格式化收口PR #613,by @soimy
    • format / format:check 的 glob 由 src/*.ts 扩展为 "src/**/*.ts",并覆盖 openclaw.plugin.jsonvitest.config.ts"scripts/**/*.mjs";此前 src/card/src/messaging/src/targeting/ 等子目录长期未纳入 oxfmt(全仓 47 个源文件不合规)。
    • src/ 根级遗留的 46 个模块按架构文档迁入 gateway/targeting/messaging/card/command/platform/shared/ 与既有 ack-reaction/src/channel.ts 保持为唯一根级装配层;不改变运行时行为。
    • CI 新增 format:check 门禁步骤,避免格式再次漂移;AGENTS.md / CLAUDE.md / docs/contributor/architecture.*.md 等文档同步为现状。

🤝 鸣谢

本版本 feat(card) 长任务进度功能源自 PR #605(by @jznrhnn)。该 PR 在 feat/live-task-progress-card 分支上提交了可替换进度块的原始实现,并完成了基于真实钉钉客户端的初步部署验证;因开发时基于 fix/openclaw-2026.8-sdk-compat,后由 PR #612 改基到 main 并完成两轮评审修复与真机验证后发布。感谢 @jznrhnn 的原始设计与实现。

同时感谢:


发布页面https://github.com/soimy/openclaw-channel-dingtalk/releases/tag/v3.7.0

Full Changelog: v3.6.11...v3.7.0

Don't miss a new openclaw-channel-dingtalk release

NewReleases is sending notifications on new releases.