docs: sync documentation with current codebase

- Update event formatter count 23 -> 28 (add ping, workflow_job, status, deployment, check_suite)
- Document Telegram support end-to-end (routes, /gh commands, richheader, secrets)
- Fix route schema to use targets array and group fields (owners, emoji)
- Correct KV/D1 storage layout (msg:*, i18n:*, D1 links/send_logs)
- Note GITHUB_APP_ID/GITHUB_PRIVATE_KEY are unused; drop legacy DISCORD_CHANNEL_ID/PORT/CONFIG_PATH
- Remove stale Docker deployment section
- Update color table, branch filter compatibility, admin API endpoints
- AGENTS.md: add Documentation section requiring doc updates after functional changes
This commit is contained in:
wyf9 2026-08-05 17:22:15 +08:00
parent 68cda9f178
commit afe19795b1
No known key found for this signature in database
GPG key ID: B126966081BFDBE4
25 changed files with 621 additions and 398 deletions

View file

@ -9,13 +9,16 @@ WebHooker 需要多个密钥才能运行。本地开发时存储在 `.dev.vars`
| 变量 | 说明 |
| ----------------------- | -------------------------------------------------------- |
| `GITHUB_WEBHOOK_SECRET` | GitHub App 设置中的 Webhook 密钥 |
| `GITHUB_APP_ID` | GitHub App 的数字 ID |
| `GITHUB_PRIVATE_KEY` | App 私钥PEM 格式,用 `\n` 转义) |
| `GITHUB_CLIENT_ID` | App 设置中的 OAuth 客户端 ID |
| `GITHUB_CLIENT_SECRET` | App 设置中的 OAuth 客户端密钥 |
| `DISCORD_TOKEN` | Discord Bot Token |
| `TELEGRAM_TOKEN` | Telegram Bot TokenBotFather 获取)—— Telegram 路由必需 |
> [!NOTE]
> `GITHUB_APP_ID``GITHUB_PRIVATE_KEY` 当前未被代码使用——OAuth 流程只需要
> `GITHUB_CLIENT_ID` / `GITHUB_CLIENT_SECRET`。为兼容性保留在模式中,以备日后启用
> GitHub App 认证。
### 可选密钥
| 变量 | 说明 | 默认值 |
@ -52,6 +55,7 @@ WebHooker 内置了位于 `/admin` 的配置控制台,可在浏览器中管理
| `GET /admin/api/groups/:id/routes` | 列出某分组的路由 |
| `PUT /admin/api/groups/:id/routes` | 替换某分组的路由 |
| `GET /admin/api/logs` | 发送日志(按可访问路由过滤) |
| `GET /admin/api/logs/:id` | 单条发送日志(按权限过滤) |
控制台支持新增、编辑、删除和开关路由。保存后立即写入 KV `config:routes` 并使配置缓存失效,下一次 webhook 处理即会生效。
@ -140,6 +144,7 @@ WebHooker 内置了位于 `/admin` 的配置控制台,可在浏览器中管理
| `name` | string | 是 | 可读的分组名称 |
| `adminIds` | string[] | 是 | 可管理该分组路由的 GitHub 用户 ID 或登录名 |
| `owners` | string[] | 否 | 允许事件进入该分组的组织/用户登录名;为空表示不限制 |
| `emoji` | boolean | 否 | 是否在该分组消息中显示 emoji默认 `true` |
### 权限模型
@ -167,7 +172,7 @@ WebHooker 内置了位于 `/admin` 的配置控制台,可在浏览器中管理
- 在任何过滤器上设置 `"exclude": true` 可反转匹配逻辑NOT 逻辑)
- 非 keyword 过滤器为**精确、不区分大小写**的匹配——不支持通配符(`repo: "org/*"` 不会匹配任何内容)
- `keyword` 过滤器支持正则表达式——正则有误或超过 200 个字符时回退到子串匹配
- `branch` 过滤器适用于 push、pull_request、pull_request_review、pull_request_review_comment、create/delete、workflow_run 和 code_scanning_alert 事件
- `branch` 过滤器适用于 push、pull_request、pull_request_review、pull_request_review_comment、create/delete、workflow_run、workflow_job、check_suite、deployment 和 code_scanning_alert 事件
### 匹配值
@ -180,17 +185,27 @@ WebHooker 内置了位于 `/admin` 的配置控制台,可在浏览器中管理
## KV 存储布局
| 键模式 | 值 | TTL |
| ------------------------ | --------------------------------------------------- | ------------------ |
| `config:routes` | JSON 路由数组 | 永久 |
| `config:groups` | JSON 分组数组 | 永久 |
| `session:{id}` | 管理员会话 `{ userId, login }` | 7 天 |
| `token:{userId}` | `{ userId, accessToken, expiresAt, refreshToken? }` | 0.9 × Token 有效期 |
| `token-reverse:{sha256}` | 用于按 Token 反查的用户 id | 0.9 × Token 有效期 |
| `discord-link:{userId}` | 与 Discord 用户绑定的 GitHub 用户 id | 永久 |
| `state:{hex}` | `{ redirectTo, expiresAt, discordUserId? }` | 600 秒 |
| `delivery:{id}` | Webhook 投递 id去重标记 | 300 秒 |
| `logs:send:{ts}-{hex}` | 发送记录 | 1 小时 |
| `cmd:guild:{id}` | 已注册命令的服务器 id去重标记 | 永久 |
| `cmd:registered:global` | 全局命令已注册标记24h 去重) | 1 天 |
| `config:discord-app-id` | Discord 应用 id 缓存 | 永久 |
| 键模式 | 值 | TTL |
| ------------------------------ | ----------------------------------------------------------------------------- | ------------------ |
| `config:routes` | JSON 路由数组 | 永久 |
| `config:groups` | JSON 分组数组 | 永久 |
| `session:{id}` | 管理员会话 `{ userId, login }` | 7 天 |
| `token:{userId}` | `{ userId, accessToken, expiresAt, refreshToken? }` | 0.9 × Token 有效期 |
| `token-reverse:{sha256}` | 用于按 Token 反查的用户 id | 0.9 × Token 有效期 |
| `state:{hex}` | `{ redirectTo, expiresAt, discordUserId?, telegramUserId?, telegramChatId? }` | 600 秒 |
| `delivery:{id}` | Webhook 投递 id去重标记 | 300 秒 |
| `msg:{routeId}:{key}:{target}` | 原地更新用消息 id 追踪(如 `workflow_run` | 7 天 |
| `cmd:guild:{id}` | 已注册命令的服务器 id去重标记 | 永久 |
| `cmd:registered:global` | 全局命令已注册标记24h 去重) | 1 天 |
| `config:discord-app-id` | Discord 应用 id 缓存 | 永久 |
| `i18n:{lang}` | 翻译覆盖,合并到英文之上 | 永久 |
## D1 存储布局
D1 数据库(`DB` 绑定,数据库 `webhooker`)包含三张表:
| 表 | 用途 |
| ---------------- | ---------------------------------------------------------------------- |
| `send_logs` | 每次分发尝试一行(路由 id、事件、目标、成功/失败、耗时、错误码、详情) |
| `discord_links` | 映射 `discord_user_id``github_user_id`,用于 Discord `/gh` 命令 |
| `telegram_links` | 映射 `telegram_user_id``github_user_id`,用于 Telegram `/gh` 命令 |

View file

@ -25,8 +25,6 @@ npx wrangler kv namespace create KV
```bash
npx wrangler secret put GITHUB_WEBHOOK_SECRET
npx wrangler secret put GITHUB_APP_ID
npx wrangler secret put GITHUB_PRIVATE_KEY # PKCS#8 PEMBEGIN PRIVATE KEY
npx wrangler secret put GITHUB_CLIENT_ID
npx wrangler secret put GITHUB_CLIENT_SECRET
npx wrangler secret put DISCORD_TOKEN
@ -39,15 +37,9 @@ npx wrangler secret put ADMIN_USER_IDS # 逗号分隔的 GitHub ID/登录
不存在全局频道密钥。每条路由在 [Web 控制台](/zh/guide/configuration#web-控制台) 中声明各自的目标频道(及可选的子区/thread因此不需要 `DISCORD_CHANNEL_ID`
:::
::: warning GitHub App 私钥必须是 PKCS#8
GitHub 下发的私钥为 PKCS#1 格式(`BEGIN RSA PRIVATE KEY`。Cloudflare Workers 的 JWT 签名要求 PKCS#8,需先转换:
```bash
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt \
-in your-app.private-key.pem -out gh_pk_pkcs8.pem
```
然后将 `gh_pk_pkcs8.pem` 作为 `GITHUB_PRIVATE_KEY` 上传。
::: tip GitHub App ID / 私钥未使用
`GITHUB_APP_ID``GITHUB_PRIVATE_KEY` 当前未被代码使用——OAuth 流程只需要
`GITHUB_CLIENT_ID` / `GITHUB_CLIENT_SECRET`。无需设置(也无需进行 PKCS#8 转换)。
:::
Discord 交互通过 HTTPS Interactions Endpoint 送达,需要设置 `DISCORD_PUBLIC_KEY` 并把 **Interactions Endpoint URL** 指向 `https://your-domain/discord/interactions`。参见下方 [Interactions Endpoint](#interactions-endpoint)。
@ -79,8 +71,8 @@ Worker 现在可通过 `https://webhooker.<your-subdomain>.workers.dev` 访问
3. 设置权限:
- **Repository permissions**: Contents (read)、Issues (write)、Pull requests (write)、Metadata (read)、Checks (read)、Deployments (read)、Discussions (read)、Code scanning alerts (read)、Dependabot alerts (read)
- **Organization permissions**: Members (read) —— 如果需要
4. 订阅事件(全部 23 种支持的事件):
- Push、Pull request、Issues、Issue comment、Workflow run、Release、Create、Delete、Star、Fork、Check run、Pull request review、Pull request review comment、Commit comment、Deployment status、Member、Label、Milestone、Discussion、Discussion comment、Repository、Code scanning alert、Dependabot alert
4. 订阅事件(全部 28 种支持的事件):
- Push、Pull request、Issues、Issue comment、Workflow run、Workflow job、Status、Deployment、Deployment status、Ping、Release、Create、Delete、Star、Fork、Check run、Check suite、Pull request review、Pull request review comment、Commit comment、Member、Label、Milestone、Discussion、Discussion comment、Repository、Code scanning alert、Dependabot alert
5. 生成私钥 → 将内容保存到 `GITHUB_PRIVATE_KEY` 环境变量
### 2. 安装 App
@ -120,6 +112,22 @@ Worker 现在可通过 `https://webhooker.<your-subdomain>.workers.dev` 访问
用户运行 `/gh login` 绑定自己的 GitHub 账号,即可以本人身份评论 issue/PR。完整命令说明见 [README](https://github.com/ReCloudStudio/WebHooker#bot-commands-comment-on-github-as-yourself)。
## Telegram 机器人配置
1. 用 [@BotFather](https://t.me/BotFather) 创建机器人,将 Token 复制到 `TELEGRAM_TOKEN`
2. (可选)设置 `TELEGRAM_WEBHOOK_SECRET`webhook 注册时会作为 `secret_token` 传给 Telegram`POST /telegram/webhook` 使用时间安全比较校验。
3. Worker 会在定时任务中自动同步 webhook`setWebhook` 指向 `{BASE_URL}/telegram/webhook`),因此无需手动调用 `setWebhook`——只需确保 `BASE_URL` 已设置。
4. 将机器人加入群组(或启用话题),在路由配置中用 `chatId` / `topicId` 指定目标。
在 Telegram 中,`/gh` 命令通过在通知消息上**回复**来使用:
- `/gh login` — 绑定你的 GitHub 账号(返回 OAuth 链接)
- `/gh logout` — 解除绑定
- `/gh comment <内容>` — 回复一条 issue/PR 通知,以本人身份评论
- `/gh merge` / `/gh close` — 回复一条 PR 通知,合并/关闭该 PR
头像使用内置 `GET /api/richheader` 渲染为链接预览卡片(可用 `TELEGRAM_RICH_HEADER_HOST` 覆盖)。
## 自定义域名(可选)
要使用自定义域名替代 `*.workers.dev`
@ -128,13 +136,5 @@ Worker 现在可通过 `https://webhooker.<your-subdomain>.workers.dev` 访问
2. 添加自定义域名或路由
3. 更新 `BASE_URL` 以匹配
## Docker
提供 Dockerfile 用于容器化部署(例如在反向代理后面):
```bash
docker build -t webhooker .
docker run -p 8787:8787 --env-file .env webhooker
```
注意Docker 模式下不包含 KV 等 Cloudflare 存储。完整功能请使用 Cloudflare 部署。
> [!NOTE]
> 本项目是一个 Cloudflare Worker依赖 `wrangler.jsonc` 中声明的 KV 与 D1 绑定,无法作为独立的 Node/容器进程运行。

View file

@ -84,13 +84,16 @@
匹配事件涉及的分支。何种字段算作「分支」取决于事件类型:
| 事件 | 提取的分支 |
| --------------------------- | ------------------------------ |
| `push` | 推送到的目标分支 |
| `pull_request`(及 review | 拉取请求的 **head**(源)分支 |
| `create` / `delete` | 创建/删除的分支或标签 |
| `workflow_run` | 工作流运行所在的 `head_branch` |
| `code_scanning_alert` | 告警所属的分支 |
| 事件 | 提取的分支 |
| --------------------------- | ----------------------------------- |
| `push` | 推送到的目标分支 |
| `pull_request`(及 review | 拉取请求的 **head**(源)分支 |
| `create` / `delete` | 创建/删除的分支或标签 |
| `workflow_run` | 工作流运行所在的 `head_branch` |
| `workflow_job` | 作业运行所在的 `head_branch` |
| `check_suite` | 检查套件的 `head_branch` |
| `deployment` | 部署引用(去除 `refs/heads/` 前缀) |
| `code_scanning_alert` | 告警所属的分支 |
```json
{

View file

@ -29,8 +29,6 @@ cp .env.example .dev.vars
```bash
GITHUB_WEBHOOK_SECRET=your-webhook-secret
GITHUB_APP_ID=your-app-id
GITHUB_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
GITHUB_CLIENT_ID=your-client-id
GITHUB_CLIENT_SECRET=your-client-secret
DISCORD_TOKEN=your-bot-token
@ -40,7 +38,7 @@ BASE_URL=http://localhost:8787
```
::: tip
`GITHUB_PRIVATE_KEY` 必须是 **PKCS#8** 格式(`BEGIN PRIVATE KEY`)。用 `openssl pkcs8 -nocrypt -in app.pem -out pkcs8.pem` 转换 GitHub 下发的 PKCS#1 私钥。目标频道在 Web UI 中按路由设置,因此不需要 `DISCORD_CHANNEL_ID`。若要在本地启用 `/gh` 命令,请在开发者门户复制 **Public Key** 填入 `DISCORD_PUBLIC_KEY`,并把 Interactions Endpoint URL 设为 `http://localhost:8787/discord/interactions`
`GITHUB_APP_ID` / `GITHUB_PRIVATE_KEY` 未被代码使用OAuth 流程只需要 Client ID/Secret可省略。目标频道在 Web UI 中按路由设置,因此不需要 `DISCORD_CHANNEL_ID`。若要在本地启用 `/gh` 命令,请在开发者门户复制 **Public Key** 填入 `DISCORD_PUBLIC_KEY`,并把 Interactions Endpoint URL 设为 `http://localhost:8787/discord/interactions`
:::
::: warning

View file

@ -1,27 +1,29 @@
# 简介
WebHooker 是一个基于 Cloudflare Workers 构建的 GitHub webhook 调度器。它接收 GitHub webhook 事件,应用可配置的过滤器,将事件格式化为丰富的 Discord 嵌入消息,并通过 Discord REST API 投递到 Discord 频道或帖子。Discord 内的 `/gh` 交互通过 HTTPS Interactions EndpointEd25519 验签)送达。路由通过内置的 Web UI 管理。
WebHooker 是一个基于 Cloudflare Workers 构建的 GitHub webhook 调度器。它接收 GitHub webhook 事件,应用可配置的过滤器,将事件格式化为富消息,并通过各自 REST API 投递到 Discord 频道/子区embed与 Telegram 群组/话题HTML。Discord 内的 `/gh` 交互通过 HTTPS Interactions EndpointEd25519 验签送达Telegram 的 `/gh` 命令通过 Telegram webhook 送达。路由与分组通过内置的 Web UI 管理。
## 架构
```text
GitHub Webhook → Cloudflare Worker (Hono)
├── POST /webhook → 验证 → 去重 → 过滤 → 格式化 → Discord (REST API)
├── POST /webhook → 验证 → 去重 → 过滤 → 格式化 → Discord (REST) / Telegram (Bot API)
├── POST /discord/interactions → 验证 (Ed25519) → 处理 /gh 斜杠与右键命令
├── POST /telegram/webhook → 验证 (secret token) → 处理 /gh 命令
├── GET /auth/github → OAuth 流程
├── GET /api/richheader → Telegram 头像链接预览卡片
├── POST /api/* → 用户操作 (Bearer Token 鉴权)
├── /admin → 路由与发送日志 Web UI管理员会话
├── /admin → 路由、分组与发送日志 Web UI管理员会话
└── GET /health → 健康检查
POST /discord/interactions → 验证 (Ed25519) → 处理 /gh 斜杠与右键命令
```
### 组件
| 组件 | 职责 |
| ------------------------- | --------------------------------------------------------------------------------------------------------- |
| **Cloudflare Worker** | HTTP 入口、签名验证、投递去重、事件解析、路由匹配、REST 发送 |
| **Interactions Endpoint** | 验证 Ed25519 签名并处理 `/gh` 交互斜杠命令、右键菜单、按钮、modal |
| **KV** | Token 存储 (`token:{userId}`)、OAuth 状态 (`state:{hex}`)、路由配置 (`config:routes`)、发送日志、投递去重 |
| 组件 | 职责 |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Cloudflare Worker** | HTTP 入口、签名验证、投递去重、事件解析、路由匹配、平台分发 |
| **Interactions Endpoint** | 验证 Ed25519 签名并处理 `/gh` 交互斜杠命令、右键菜单、按钮、modal |
| **KV** | Token 存储 (`token:{userId}`)、OAuth 状态 (`state:{hex}`)、路由配置 (`config:routes`)、分组配置 (`config:groups`)、管理员会话、投递去重、消息更新追踪 (`msg:*`) |
| **D1** | 发送日志 (`send_logs`)、Discord↔GitHub 绑定 (`discord_links`)、Telegram↔GitHub 绑定 (`telegram_links`) |
### 数据流
@ -29,18 +31,19 @@ POST /discord/interactions → 验证 (Ed25519) → 处理 /gh 斜杠与右键
2. Worker 验证 HMAC-SHA256 签名
3. Worker 按 `X-GitHub-Delivery` 去重KV短 TTL丢弃重复投递
4. Worker 解析事件类型和载荷
5. 根据过滤器评估路由event、repo、actor、action、branch、keyword
6. 匹配的路由触发格式化器函数生成 Discord 嵌入消息
7. 每条消息通过 Discord REST API 发送到对应路由的目标频道/帖子,并处理速率限制重试,结果记录到发送日志
5. 根据过滤器event、repo、actor、action、branch、keyword与分组所有者限制评估路由
6. 匹配的路由触发格式化器函数生成平台中立消息
7. 每条消息通过 Discord 或 Telegram REST API 发送到对应路由的目标,并处理速率限制重试;`workflow_run` 进度原地更新。每次尝试都记录到 D1 发送日志
## 技术栈
- **运行时**: Cloudflare Workers
- **HTTP 框架**: Hono
- **Discord 投递**: Discord REST API交互通过 Ed25519 验签的 HTTPS Interactions Endpoint
- **Telegram 投递**: Telegram Bot APIwebhook 带可选 secret-token 校验)
- **Web UI**: Nuxt 3 静态 SPA由 Worker 资源托管
- **存储**: Cloudflare KV
- **鉴权**: Web Crypto API (HMAC-SHA256)、jose (JWT)、octokit (GitHub API)
- **存储**: Cloudflare KV + D1
- **鉴权**: Web Crypto API (HMAC-SHA256、Ed25519)、octokit (GitHub API)、jose依赖
- **语言**: TypeScript
## 许可证