跳到主要内容

Webhooks

从外部服务(GitHub、GitLab、JIRA、Stripe 等)接收事件,并自动触发 Hermes 代理运行。Webhook 适配器运行一个 HTTP 服务器,接收 POST 请求,验证 HMAC 签名,将有效载荷转换为代理提示,并将响应路由回源服务或另一个配置的平台。

代理处理事件后,可以回复评论到 PR、向 Telegram/Discord 发送消息,或记录结果。


快速入门

  1. 通过 hermes gateway setup 或环境变量启用
  2. config.yaml 中定义路由 使用 hermes webhook subscribe 动态创建路由
  3. 将你的服务指向 http://your-server:8644/webhooks/<route-name>

设置

有两种方式可以启用 Webhook 适配器。

通过设置向导

hermes gateway setup

按照提示启用 Webhooks,设置端口,并设置全局 HMAC 密钥。

通过环境变量

将以下内容添加到 ~/.hermes/.env

WEBHOOK_ENABLED=true
WEBHOOK_PORT=8644 # default
WEBHOOK_SECRET=your-global-secret

验证服务器

一旦网关启动运行:

curl http://localhost:8644/health

预期响应:

{"status": "ok", "platform": "webhook"}

配置路由

路由定义了如何处理不同的 Webhook 源。每个路由是 config.yamlplatforms.webhook.extra.routes 下的一个命名条目。

路由属性

属性必填描述
events要接受的事件类型列表(例如 ["pull_request"])。如果为空,则接受所有事件。事件类型从 X-GitHub-EventX-GitLab-Event 或有效载荷中的 event_type 读取。
secret用于签名验证的 HMAC 密钥。如果路由未设置,则回退到全局 secret。仅用于测试时设置为 "INSECURE_NO_AUTH"(跳过验证)。
prompt包含点号表示法有效载荷访问的模板字符串(例如 {pull_request.title})。如果省略,则将完整 JSON 有效载荷转储到提示中。
skills为代理运行加载的技能名称列表。
deliver响应发送位置:github_commenttelegramdiscordslacksignalsmswhatsappmatrixmattermosthomeassistantemaildingtalkfeishuwecomweixinbluebubbleslog(默认)。
deliver_extra额外的交付配置 —— 键取决于 deliver 类型(例如 repopr_numberchat_id)。值支持与 prompt 相同的 {dot.notation} 模板。

完整示例

platforms:
webhook:
enabled: true
extra:
port: 8644
secret: "global-fallback-secret"
routes:
github-pr:
events: ["pull_request"]
secret: "github-webhook-secret"
prompt: |
Review this pull request:
Repository: {repository.full_name}
PR #{number}: {pull_request.title}
Author: {pull_request.user.login}
URL: {pull_request.html_url}
Diff URL: {pull_request.diff_url}
Action: {action}
skills: ["github-code-review"]
deliver: "github_comment"
deliver_extra:
repo: "{repository.full_name}"
pr_number: "{number}"
deploy-notify:
events: ["push"]
secret: "deploy-secret"
prompt: "New push to {repository.full_name} branch {ref}: {head_commit.message}"
deliver: "telegram"

提示模板

提示使用点号表示法访问 Webhook 有效载荷中的嵌套字段:

  • {pull_request.title} 解析为 payload["pull_request"]["title"]
  • {repository.full_name} 解析为 payload["repository"]["full_name"]
  • {__raw__} —— 特殊标记,将 整个有效载荷 以缩进的 JSON 格式转储(截断为 4000 个字符)。适用于监控警报或通用 Webhook,其中代理需要完整上下文。
  • 缺失的键将保留为字面量 {key}(无错误)
  • 嵌套字典和列表将被 JSON 序列化,并在 2000 个字符处截断

你可以将 {__raw__} 与常规模板变量混合使用:

prompt: "PR #{pull_request.number} by {pull_request.user.login}: {__raw__}"

如果某个路由未配置 prompt 模板,则整个有效载荷将以缩进的 JSON 格式转储(截断为 4000 个字符)。

相同的点号表示法模板也适用于 deliver_extra 值。

论坛主题交付

当向 Telegram 交付 Webhook 响应时,可以通过在 deliver_extra 中包含 message_thread_id(或 thread_id)来定位特定论坛主题:

webhooks:
routes:
alerts:
events: ["alert"]
prompt: "Alert: {__raw__}"
deliver: "telegram"
deliver_extra:
chat_id: "-1001234567890"
message_thread_id: "42"

如果 deliver_extra 中未提供 chat_id,交付将回退到目标平台配置的主频道。


GitHub PR 审查(逐步指南)

本指南将设置在每次拉取请求上自动进行代码审查。

1. 在 GitHub 中创建 Webhook

  1. 进入你的仓库 → 设置Webhooks添加 Webhook
  2. 设置 有效载荷 URLhttp://your-server:8644/webhooks/github-pr
  3. 设置 内容类型application/json
  4. 设置 密钥 以匹配你的路由配置(例如 github-webhook-secret
  5. 哪些事件? 下,选择 让我选择单个事件,并勾选 拉取请求
  6. 点击 添加 Webhook

2. 添加路由配置

github-pr 路由添加到你的 ~/.hermes/config.yaml,如上例所示。

3. 确保 gh CLI 已认证

github_comment 交付类型使用 GitHub CLI 发布评论:

gh auth login

4. 测试

在仓库中打开一个拉取请求。Webhook 触发,Hermes 处理事件,并在 PR 上发布审查评论。


GitLab Webhook 设置

GitLab Webhook 的工作方式类似,但使用不同的认证机制。GitLab 以明文 X-Gitlab-Token 头发送密钥(精确字符串匹配,非 HMAC)。

  1. 进入您的项目 → 设置Webhooks
  2. URL 设置为 http://your-server:8644/webhooks/gitlab-mr
  3. 输入您的 密钥令牌
  4. 选择 合并请求事件(以及您想要的其他事件)
  5. 点击 添加 Webhook

2. 添加路由配置

platforms:
webhook:
enabled: true
extra:
routes:
gitlab-mr:
events: ["merge_request"]
secret: "your-gitlab-secret-token"
prompt: |
Review this merge request:
Project: {project.path_with_namespace}
MR !{object_attributes.iid}: {object_attributes.title}
Author: {object_attributes.last_commit.author.name}
URL: {object_attributes.url}
Action: {object_attributes.action}
deliver: "log"

交付选项

deliver 字段控制代理在处理 Webhook 事件后,将响应发送到何处。

交付类型描述
log将响应记录到网关日志输出中。这是默认选项,适用于测试。
github_comment通过 gh CLI 将响应作为 PR/问题评论发布。需要 deliver_extra.repodeliver_extra.pr_numbergh CLI 必须在网关主机上安装并已认证(gh auth login)。
telegram将响应路由至 Telegram。使用主频道,或在 deliver_extra 中指定 chat_id
discord将响应路由至 Discord。使用主频道,或在 deliver_extra 中指定 chat_id
slack将响应路由至 Slack。使用主频道,或在 deliver_extra 中指定 chat_id
signal将响应路由至 Signal。使用主频道,或在 deliver_extra 中指定 chat_id
sms通过 Twilio 将响应路由至短信。使用主频道,或在 deliver_extra 中指定 chat_id
whatsapp将响应路由至 WhatsApp。使用主频道,或在 deliver_extra 中指定 chat_id
matrix将响应路由至 Matrix。使用主频道,或在 deliver_extra 中指定 chat_id
mattermost将响应路由至 Mattermost。使用主频道,或在 deliver_extra 中指定 chat_id
homeassistant将响应路由至 Home Assistant。使用主频道,或在 deliver_extra 中指定 chat_id
email将响应路由至电子邮件。使用主频道,或在 deliver_extra 中指定 chat_id
dingtalk将响应路由至钉钉。使用主频道,或在 deliver_extra 中指定 chat_id
feishu将响应路由至飞书/飞书。使用主频道,或在 deliver_extra 中指定 chat_id
wecom将响应路由至企业微信。使用主频道,或在 deliver_extra 中指定 chat_id
weixin将响应路由至微信(WeChat)。使用主频道,或在 deliver_extra 中指定 chat_id
bluebubbles将响应路由至 BlueBubbles(iMessage)。使用主频道,或在 deliver_extra 中指定 chat_id

对于跨平台交付,目标平台也必须在网关中启用并已连接。如果 deliver_extra 中未提供 chat_id,响应将发送至该平台配置的主频道。


动态订阅(CLI)

除了 config.yaml 中的静态路由外,您还可以使用 hermes webhook CLI 命令动态创建 Webhook 订阅。这在代理自身需要设置事件驱动触发器时特别有用。

创建订阅

hermes webhook subscribe github-issues \
--events "issues" \
--prompt "New issue #{issue.number}: {issue.title}\nBy: {issue.user.login}\n\n{issue.body}" \
--deliver telegram \
--deliver-chat-id "-100123456789" \
--description "Triage new GitHub issues"

此命令将返回 Webhook URL 和自动生成的 HMAC 密钥。请配置您的服务向该 URL 发送 POST 请求。

列出订阅

hermes webhook list

删除订阅

hermes webhook remove github-issues

测试订阅

hermes webhook test github-issues
hermes webhook test github-issues --payload '{"issue": {"number": 42, "title": "Test"}}'

动态订阅的工作原理

  • 订阅信息存储在 ~/.hermes/webhook_subscriptions.json
  • Webhook 适配器在每次接收到请求时热重载该文件(基于修改时间,开销可忽略)
  • config.yaml 中的静态路由始终优先于同名的动态路由
  • 动态订阅使用与静态路由相同的路由格式和功能(事件、提示模板、技能、交付)
  • 无需重启网关 —— 订阅后立即生效

代理驱动的订阅

代理可通过终端工具在 webhook-subscriptions 技能的引导下创建订阅。例如,让代理“为 GitHub 问题设置 Webhook”,它将自动执行相应的 hermes webhook subscribe 命令。


安全性

Webhook 适配器包含多层安全机制:

HMAC 签名验证

适配器使用每个源对应的适当方法验证传入的 Webhook 签名:

  • GitHubX-Hub-Signature-256 头 —— HMAC-SHA256 十六进制摘要,前缀为 sha256=
  • GitLabX-Gitlab-Token 头 —— 纯密钥字符串匹配
  • 通用X-Webhook-Signature 头 —— 原始 HMAC-SHA256 十六进制摘要

如果配置了密钥但未检测到可识别的签名头,请求将被拒绝。

密钥为必需项

每个路由都必须设置密钥 —— 要么直接在路由中设置,要么从全局 secret 继承。未设置密钥的路由会导致适配器在启动时失败并报错。仅用于开发/测试时,可将密钥设为 "INSECURE_NO_AUTH" 以完全跳过验证。

速率限制

每个路由默认限制为 每分钟 30 次请求(固定窗口)。可全局配置:

platforms:
webhook:
extra:
rate_limit: 60 # requests per minute

超过限制的请求将收到 429 Too Many Requests 响应。

幂等性

交付 ID(来自 X-GitHub-DeliveryX-Request-ID 或时间戳回退)会被缓存 1 小时。重复的交付(例如 Webhook 重试)将被静默跳过,并返回 200 响应,从而防止重复执行代理。

请求体大小限制

超过 1 MB 的负载在读取请求体之前即被拒绝。可进行如下配置:

platforms:
webhook:
extra:
max_body_bytes: 2097152 # 2 MB

提示注入风险

注意

Webhook 负载包含攻击者控制的数据——PR 标题、提交信息、问题描述等都可能包含恶意指令。当网关暴露在互联网时,建议在沙箱环境(如 Docker、虚拟机)中运行。考虑使用 Docker 或 SSH 终端后端以实现隔离。


故障排除

Webhook 未到达

  • 确认端口已暴露且可从 Webhook 源访问
  • 检查防火墙规则——端口 8644(或您配置的端口)必须开放
  • 确认 URL 路径匹配:http://your-server:8644/webhooks/<route-name>
  • 使用 /health 端点确认服务器正在运行

签名验证失败

  • 确保路由配置中的密钥与 Webhook 源中配置的密钥完全一致
  • 对于 GitHub,密钥基于 HMAC —— 检查 X-Hub-Signature-256
  • 对于 GitLab,密钥为明文令牌匹配 —— 检查 X-Gitlab-Token
  • 检查网关日志中的 Invalid signature 警告

事件被忽略

  • 检查事件类型是否在路由的 events 列表中
  • GitHub 事件使用如 pull_requestpushissues 等值(即 X-GitHub-Event 请求头的值)
  • GitLab 事件使用如 merge_requestpush 等值(即 X-GitLab-Event 请求头的值)
  • 如果 events 为空或未设置,则接受所有事件

代理无响应

  • 以前台模式运行网关以查看日志:hermes gateway run
  • 检查提示模板是否正确渲染
  • 确认交付目标已正确配置并已连接

重复响应

  • 幂等性缓存应可防止此问题——检查 Webhook 源是否发送了交付 ID 请求头(X-GitHub-DeliveryX-Request-ID
  • 交付 ID 缓存时间为 1 小时

gh CLI 错误(GitHub 评论交付)

  • 在网关主机上运行 gh auth login
  • 确保已认证的 GitHub 用户对仓库具有写入权限
  • 检查 gh 是否已安装且在 PATH 中

环境变量

变量描述默认值
WEBHOOK_ENABLED启用 Webhook 平台适配器false
WEBHOOK_PORT接收 Webhook 的 HTTP 服务器端口8644
WEBHOOK_SECRET全局 HMAC 密钥(当路由未指定自身密钥时作为回退)(无)