mirror of
https://github.com/ReCloudStudio/WebHooker.git
synced 2026-09-22 16:11:29 +00:00
docs: restructure into core-concept pages and split admin API
This commit is contained in:
parent
db49e1f01c
commit
a9e50fba50
27 changed files with 946 additions and 1203 deletions
39
docs/zh/api/admin.md
Normal file
39
docs/zh/api/admin.md
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Admin API
|
||||
|
||||
管理端点用于管理路由、分组、成员、邀请、webhook 密钥、发送日志与审计日志。它们需要会话 Cookie,可通过 `GET /admin/login`(GitHub OAuth)获取;登录用户必须列在 `ADMIN_USER_IDS` 中,或管理某个分组。设置方法见[配置 → Web 控制台](../guide/configuration.md#web-ui)。
|
||||
|
||||
控制台本身在 `/admin` 提供;其标签页可通过 URL 路径直达(`/admin/groups`、`/admin/logs`、`/admin/audit`)。
|
||||
|
||||
## 端点
|
||||
|
||||
| 端点 | 说明 |
|
||||
|-------------------------------------------------|-------------------------------------------------------------------|
|
||||
| `GET /admin` | 配置控制台页面 |
|
||||
| `GET /admin/login` | 开始管理员登录(GitHub OAuth) |
|
||||
| `GET /admin/logout` | 退出登录并销毁会话 |
|
||||
| `GET /admin/invite?token=…` | 接受分组邀请(浏览器页面) |
|
||||
| `GET /admin/api/me` | 当前会话、权限范围、分组与角色 |
|
||||
| `GET /admin/api/routes` | 列出路由(按权限过滤) |
|
||||
| `PUT /admin/api/routes` | 替换路由(按分组 owner/admin) |
|
||||
| `GET /admin/api/groups` | 列出分组 + 当前用户在各分组的角色 |
|
||||
| `PUT /admin/api/groups` | 替换分组(超级管理员全部;owner 仅自己的) |
|
||||
| `GET /admin/api/groups/:id/routes` | 列出某分组的路由 |
|
||||
| `PUT /admin/api/groups/:id/routes` | 替换某分组的路由(owner/admin) |
|
||||
| `PUT /admin/api/groups/:id/rename` | 重命名分组(owner);路由、webhook secret 与邀请自动跟随 |
|
||||
| `GET /admin/api/groups/:id/invites` | 列出待处理的邀请(owner) |
|
||||
| `POST /admin/api/groups/:id/invites` | 创建邀请链接(owner) |
|
||||
| `DELETE /admin/api/invites/:token` | 撤销邀请(owner) |
|
||||
| `GET /admin/api/groups/:id/webhook` | 分组 webhook 端点信息(owner) |
|
||||
| `POST /admin/api/groups/:id/webhook/regenerate` | 生成/重新生成分组 webhook secret(owner) |
|
||||
| `DELETE /admin/api/groups/:id/webhook` | 停用分组 webhook 入口(owner) |
|
||||
| `GET /admin/api/logs` | 发送日志(按可访问的路由过滤) |
|
||||
| `GET /admin/api/logs/:id` | 单条发送日志(按权限过滤) |
|
||||
| `GET /admin/api/audit` | 审计日志(按可访问的分组过滤) |
|
||||
|
||||
## 校验
|
||||
|
||||
- `PUT /admin/api/routes` — 请求体为 `{ "routes": Route[] }`;校验每条路由(id 格式、组内唯一 id、name、enabled、groupId、过滤器——**仅 `fallback` 路由允许空过滤器**——可选的 `discordRoleIds`(身份组 id 字符串列表)、平台感知的 targets:Discord 需 `target.channelId`,Telegram 需 `target.chatId`)并持久化到 KV `config:routes`。返回 `200 { ok, count }` 或 `400 { error }` / `401 { error }` / `403 { error }`。未变更的路由跳过完整校验。
|
||||
- `PUT /admin/api/groups` — 校验分组 id、成员角色(至少一个 `owner`)、`providers`(`github` / `gitea`)与 `installationId`。
|
||||
- 上限:每个实例最多 200 条路由与 100 个分组。
|
||||
|
||||
模式:见[路由与目标](../guide/routes)、[分组与访问控制](../guide/groups)。
|
||||
|
|
@ -10,52 +10,33 @@ https://your-worker.workers.dev
|
|||
|
||||
## 端点
|
||||
|
||||
| 方法 | 路径 | 鉴权 | 说明 |
|
||||
|----------|--------------------------------------------|--------------|------------------------------------------------------|
|
||||
| `GET` | `/health` | 无 | 健康检查 |
|
||||
| `POST` | `/webhook` | HMAC 签名 | GitHub / Gitea / 自定义 webhook 接入(自动识别来源) |
|
||||
| `POST` | `/webhook/:groupId` | 分组 secret | 分组级 webhook 入口(只触发该分组的路由) |
|
||||
| `POST` | `/discord/interactions` | Ed25519 签名 | Discord 交互(斜杠命令、按钮、modal) |
|
||||
| `POST` | `/telegram/webhook` | Secret token | Telegram 更新(bot `/gh` 命令) |
|
||||
| `GET` | `/api/richheader` | 无 | 用于 Telegram 头像链接预览卡片的 Open Graph 页面 |
|
||||
| `GET` | `/auth/github` | 无 | 启动 GitHub OAuth 流程 |
|
||||
| `GET` | `/auth/github/callback` | 无 | OAuth 回调 |
|
||||
| `GET` | `/auth/github/install` | 管理员会话 | 安装后选择页:将安装绑定到某个分组 |
|
||||
| `POST` | `/auth/github/install/bind` | 管理员会话 | 执行选定的安装绑定 |
|
||||
| `DELETE` | `/auth/token/:userId` | 管理员会话 | 撤销用户 Token |
|
||||
| `POST` | `/api/comment` | Bearer Token | 创建议题评论 |
|
||||
| `POST` | `/api/merge` | Bearer Token | 合并拉取请求 |
|
||||
| `POST` | `/api/close` | Bearer Token | 关闭拉取请求 |
|
||||
| `POST` | `/api/react` | Bearer Token | 添加议题反应 |
|
||||
| `GET` | `/admin` | 管理员会话 | 配置控制台页面 |
|
||||
| `GET` | `/admin/login` | 无 | 开始管理员登录(GitHub OAuth) |
|
||||
| `GET` | `/admin/logout` | 管理员会话 | 退出登录并销毁会话 |
|
||||
| `GET` | `/admin/invite` | 管理员会话 | 接受分组邀请(浏览器页面,`?token=…`) |
|
||||
| `GET` | `/admin/api/me` | 管理员会话 | 当前会话、权限范围、分组与角色 |
|
||||
| `GET` | `/admin/api/routes` | 管理员会话 | 列出路由(按权限过滤) |
|
||||
| `PUT` | `/admin/api/routes` | 管理员会话 | 替换路由(按分组 owner/admin) |
|
||||
| `GET` | `/admin/api/groups` | 管理员会话 | 列出分组 + 当前用户在各分组的角色 |
|
||||
| `PUT` | `/admin/api/groups` | 管理员会话 | 替换分组(超级管理员全部;owner 仅自己的) |
|
||||
| `GET` | `/admin/api/groups/:id/routes` | 管理员会话 | 列出某分组的路由 |
|
||||
| `PUT` | `/admin/api/groups/:id/routes` | 管理员会话 | 替换某分组的路由(owner/admin) |
|
||||
| `PUT` | `/admin/api/groups/:id/rename` | 管理员会话 | 重命名分组(owner);路由/secret/邀请自动跟随 |
|
||||
| `GET` | `/admin/api/groups/:id/invites` | 管理员会话 | 列出待处理的邀请(owner) |
|
||||
| `POST` | `/admin/api/groups/:id/invites` | 管理员会话 | 创建邀请链接(owner) |
|
||||
| `DELETE` | `/admin/api/invites/:token` | 管理员会话 | 撤销邀请(owner) |
|
||||
| `GET` | `/admin/api/groups/:id/webhook` | 管理员会话 | 分组 webhook 端点信息(owner) |
|
||||
| `POST` | `/admin/api/groups/:id/webhook/regenerate` | 管理员会话 | 生成/重新生成分组 webhook secret(owner) |
|
||||
| `DELETE` | `/admin/api/groups/:id/webhook` | 管理员会话 | 停用分组 webhook 入口(owner) |
|
||||
| `GET` | `/admin/api/logs` | 管理员会话 | 发送日志(按权限过滤) |
|
||||
| `GET` | `/admin/api/logs/:id` | 管理员会话 | 单条发送日志(按权限过滤) |
|
||||
| `GET` | `/admin/api/audit` | 管理员会话 | 审计日志(按可访问的分组过滤) |
|
||||
| 方法 | 路径 | 鉴权 | 说明 |
|
||||
|------------|----------------------------------------------|----------------|--------------------------------------------------------|
|
||||
| `GET` | `/health` | 无 | 健康检查 |
|
||||
| `POST` | `/webhook` | HMAC 签名 | GitHub / Gitea / 自定义 webhook 接入(自动识别来源) |
|
||||
| `POST` | `/webhook/:groupId` | 分组 secret | 分组级 webhook 入口(只触发该分组的路由) |
|
||||
| `POST` | `/discord/interactions` | Ed25519 签名 | Discord 交互(斜杠命令、按钮、modal) |
|
||||
| `POST` | `/telegram/webhook` | Secret token | Telegram 更新(bot `/gh` 命令) |
|
||||
| `GET` | `/api/richheader` | 无 | 用于 Telegram 头像链接预览卡片的 Open Graph 页面 |
|
||||
| `GET` | `/auth/github` | 无 | 启动 GitHub OAuth 流程 |
|
||||
| `GET` | `/auth/github/callback` | 无 | OAuth 回调 |
|
||||
| `GET` | `/auth/github/install` | 管理员会话 | 安装后选择页:将安装绑定到某个分组 |
|
||||
| `POST` | `/auth/github/install/bind` | 管理员会话 | 执行选定的安装绑定 |
|
||||
| `DELETE` | `/auth/token/:userId` | 管理员会话 | 撤销用户 Token |
|
||||
| `POST` | `/api/comment` | Bearer Token | 创建议题评论 |
|
||||
| `POST` | `/api/merge` | Bearer Token | 合并拉取请求 |
|
||||
| `POST` | `/api/close` | Bearer Token | 关闭拉取请求 |
|
||||
| `POST` | `/api/react` | Bearer Token | 添加议题反应 |
|
||||
| `GET` | `/admin` | 管理员会话 | 配置控制台页面 |
|
||||
| `GET` | `/admin/login` | 无 | 开始管理员登录(GitHub OAuth) |
|
||||
| `GET` | `/admin/logout` | 管理员会话 | 退出登录并销毁会话 |
|
||||
| `GET` | `/admin/invite` | 管理员会话 | 接受分组邀请(浏览器页面,`?token=…`) |
|
||||
|
||||
`/admin/api/*` 端点(路由、分组、成员、邀请、webhook 密钥、发送日志、审计日志)在 [Admin API](./admin) 中单独说明。
|
||||
|
||||
## 管理控制台
|
||||
|
||||
参见[配置 → Web 控制台](../guide/configuration.md#web-ui)了解设置方法。管理端点需要会话 Cookie,可通过 `GET /admin/login`(GitHub OAuth)获取;登录用户必须列在 `ADMIN_USER_IDS` 中,或管理某个分组。
|
||||
|
||||
- `GET /admin` — 提供配置控制台 HTML
|
||||
- `GET /admin/api/routes` — 返回 `{ "routes": Route[] }`
|
||||
- `PUT /admin/api/routes` — 请求体为 `{ "routes": Route[] }`;校验每条路由(id 格式、唯一 id、name、enabled、groupId、过滤器——**仅 `fallback` 路由允许空过滤器**——可选的 `discordRoleIds`(身份组 id 字符串列表)、平台感知的 targets:Discord 需 `target.channelId`,Telegram 需 `target.chatId`)并持久化到 KV `config:routes`。返回 `200 { ok, count }` 或 `400 { error }` / `401 { error }` / `403 { error }`。
|
||||
参见[配置 → Web 控制台](../guide/configuration.md#web-ui)了解设置方法,管理端点的完整参考见 [Admin API](./admin)。管理端点需要会话 Cookie,可通过 `GET /admin/login`(GitHub OAuth)获取;登录用户必须列在 `ADMIN_USER_IDS` 中,或管理某个分组。
|
||||
|
||||
## 健康检查
|
||||
|
||||
|
|
@ -81,11 +62,11 @@ POST /webhook
|
|||
|
||||
**请求头:**
|
||||
|
||||
| 头部 | 必需 | 说明 |
|
||||
|-----------------------|------|-------------------------------|
|
||||
| `X-Hub-Signature-256` | 是 | HMAC-SHA256 签名 |
|
||||
| `X-GitHub-Event` | 是 | 事件类型名称 |
|
||||
| `X-GitHub-Delivery` | 否 | 唯一投递 ID(存在时用于去重) |
|
||||
| 头部 | 必需 | 说明 |
|
||||
|-------------------------|--------|---------------------------------|
|
||||
| `X-Hub-Signature-256` | 是 | HMAC-SHA256 签名 |
|
||||
| `X-GitHub-Event` | 是 | 事件类型名称 |
|
||||
| `X-GitHub-Delivery` | 否 | 唯一投递 ID(存在时用于去重) |
|
||||
|
||||
**请求体:** GitHub webhook JSON 载荷(最大 1MB)。
|
||||
|
||||
|
|
@ -101,11 +82,11 @@ POST /webhook
|
|||
|
||||
**错误响应:**
|
||||
|
||||
| 状态码 | 响应体 | 原因 |
|
||||
|--------|----------------------------------|------------------------------|
|
||||
| `401` | `{"error": "Invalid signature"}` | 签名验证失败 |
|
||||
| `400` | `{"error": "Invalid event"}` | 缺少事件头或格式错误的请求体 |
|
||||
| `413` | `{"error": "Request too large"}` | 请求体超过 1MB 限制 |
|
||||
| 状态码 | 响应体 | 原因 |
|
||||
|----------|------------------------------------|--------------------------------|
|
||||
| `401` | `{"error": "Invalid signature"}` | 签名验证失败 |
|
||||
| `400` | `{"error": "Invalid event"}` | 缺少事件头或格式错误的请求体 |
|
||||
| `413` | `{"error": "Request too large"}` | 请求体超过 1MB 限制 |
|
||||
|
||||
### 分组级 Webhook(`POST /webhook/:groupId`)
|
||||
|
||||
|
|
@ -113,18 +94,18 @@ POST /webhook
|
|||
|
||||
### 自定义 Webhook
|
||||
|
||||
任意 JSON 载荷用 `X-WebHooker-Signature: sha256=<hex>`(对原始 body 的 HMAC-SHA256,使用分组或全局 secret)签名后即可成为 `custom` 事件。用 `event: custom` 过滤器的路由接收。载荷格式见[配置 → 自定义 Webhook](../guide/configuration.md#自定义-webhook)。
|
||||
任意 JSON 载荷用 `X-WebHooker-Signature: sha256=<hex>`(对原始 body 的 HMAC-SHA256,使用分组或全局 secret)签名后即可成为 `custom` 事件。用 `event: custom` 过滤器的路由接收。载荷格式见[配置 → 自定义 Webhook](../guide/ingress.md#自定义-webhook)。
|
||||
|
||||
### GitHub App 安装事件
|
||||
|
||||
`installation` webhook 事件(`created` 等)作为兜底会自动配置:按安装账号自动创建分组(`inst-{installationId}`,绑定 `installationId`);或把 `owners` 匹配该账号的现有分组自动绑定到该安装。参见[配置 → GitHub App 租户隔离](../guide/configuration.md#github-app-租户隔离)。
|
||||
`installation` webhook 事件(`created` 等)作为兜底会自动配置:按安装账号自动创建分组(`inst-{installationId}`,绑定 `installationId`);或把 `owners` 匹配该账号的现有分组自动绑定到该安装。参见[配置 → GitHub App 租户隔离](../guide/ingress.md#github-app-租户隔离)。
|
||||
|
||||
主要流程是 App 的 **Setup URL** —— 将其设置为 `{BASE_URL}/auth/github/install`。用户安装 App 后浏览器会跳转到:
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|--------|-----------------------------|---------------------------------------------------------------|
|
||||
| `GET` | `/auth/github/install` | 选择页:将安装绑定到新分组或登录用户拥有 owner 权限的已有分组 |
|
||||
| `POST` | `/auth/github/install/bind` | 执行绑定(再次校验 owner 角色)并跳转 `/admin?install=ok` |
|
||||
| 方法 | 路径 | 说明 |
|
||||
|----------|-------------------------------|-----------------------------------------------------------------|
|
||||
| `GET` | `/auth/github/install` | 选择页:将安装绑定到新分组或登录用户拥有 owner 权限的已有分组 |
|
||||
| `POST` | `/auth/github/install/bind` | 执行绑定(再次校验 owner 角色)并跳转 `/admin?install=ok` |
|
||||
|
||||
## 错误格式
|
||||
|
||||
|
|
|
|||
|
|
@ -4,51 +4,51 @@ WebHooker 支持 28 种 GitHub webhook 事件类型,每种都有专用的格
|
|||
|
||||
## 事件表
|
||||
|
||||
| 事件 | 说明 | 嵌入亮点 |
|
||||
|-------------------------------|---------------------------|----------------------------------------------------------------------------------------------------------------|
|
||||
| `push` | 代码推送到分支 | 提交列表、分支、作者、差异统计 |
|
||||
| `pull_request` | PR 打开/关闭/合并/编辑 | PR 标题、分支、差异统计、标签 |
|
||||
| `issues` | 议题打开/关闭/编辑 | 议题标题、标签、指派人 |
|
||||
| `issue_comment` | 议题或 PR 的评论 | 评论内容、议题引用 |
|
||||
| `workflow_run` | CI/CD 工作流阶段更新 | 工作流状态、结论、耗时;各阶段原地更新同一条消息 |
|
||||
| `workflow_job` | CI 作业阶段更新 | 作业名、状态、结论、工作流 |
|
||||
| `status` | 提交状态更新 | 提交状态、上下文、状态值、提交链接 |
|
||||
| `deployment` | 部署已创建 | 环境、引用、任务 |
|
||||
| `deployment_status` | 部署状态更新 | 环境、状态、提交引用 |
|
||||
| `check_run` | 检查运行阶段更新 | 状态、结论、详情 URL;各阶段原地更新同一条消息 |
|
||||
| `check_suite` | 检查套件完成 | 套件结论、head 分支、提交链接 |
|
||||
| `ping` | Webhook 确认 | Webhook 确认、已订阅的事件类型 |
|
||||
| `release` | 发布创建/编辑 | 标签、内容、附件、预发布标记 |
|
||||
| `create` | 分支或标签已创建 | 引用名称、引用类型 |
|
||||
| `delete` | 分支或标签已删除 | 引用名称、引用类型 |
|
||||
| `star` | 仓库加星/取消星标 | 星标数、操作 |
|
||||
| `fork` | 仓库已复刻 | 源 → 目标复刻 |
|
||||
| `pull_request_review` | PR 审查已提交 | 审查状态(已批准/需修改/已评论)、正文 |
|
||||
| `pull_request_review_comment` | 行内代码审查评论 | 文件路径、行号、评论内容 |
|
||||
| `commit_comment` | 提交的评论 | 提交 SHA、评论内容 |
|
||||
| `member` | 协作者添加/移除 | 成员登录名、操作 |
|
||||
| `label` | 标签创建/编辑/删除 | 标签名称、颜色、描述 |
|
||||
| `milestone` | 里程碑打开/关闭 | 进度条、议题计数、截止日期 |
|
||||
| `discussion` | 讨论创建/回答 | 标题、分类、操作 |
|
||||
| `discussion_comment` | 讨论的评论 | 评论内容、讨论引用 |
|
||||
| `repository` | 仓库重命名/转移 | 旧 → 新名称、变更 |
|
||||
| `code_scanning_alert` | 代码扫描告警 | 严重程度、规则 ID、文件路径 |
|
||||
| `dependabot_alert` | Dependabot 告警 | 严重程度、包、受影响版本、修复版本 |
|
||||
| `custom` | 签名的自定义 JSON webhook | 任意 title/description/color/url/author/fields(见[自定义 webhook](../guide/configuration.md#自定义-webhook)) |
|
||||
| 事件 | 说明 | 嵌入亮点 |
|
||||
|---------------------------------|-----------------------------|------------------------------------------------------------------------------------------------------------------|
|
||||
| `push` | 代码推送到分支 | 提交列表、分支、作者、差异统计 |
|
||||
| `pull_request` | PR 打开/关闭/合并/编辑 | PR 标题、分支、差异统计、标签 |
|
||||
| `issues` | 议题打开/关闭/编辑 | 议题标题、标签、指派人 |
|
||||
| `issue_comment` | 议题或 PR 的评论 | 评论内容、议题引用 |
|
||||
| `workflow_run` | CI/CD 工作流阶段更新 | 工作流状态、结论、耗时;各阶段原地更新同一条消息 |
|
||||
| `workflow_job` | CI 作业阶段更新 | 作业名、状态、结论、工作流 |
|
||||
| `status` | 提交状态更新 | 提交状态、上下文、状态值、提交链接 |
|
||||
| `deployment` | 部署已创建 | 环境、引用、任务 |
|
||||
| `deployment_status` | 部署状态更新 | 环境、状态、提交引用 |
|
||||
| `check_run` | 检查运行阶段更新 | 状态、结论、详情 URL;各阶段原地更新同一条消息 |
|
||||
| `check_suite` | 检查套件完成 | 套件结论、head 分支、提交链接 |
|
||||
| `ping` | Webhook 确认 | Webhook 确认、已订阅的事件类型 |
|
||||
| `release` | 发布创建/编辑 | 标签、内容、附件、预发布标记 |
|
||||
| `create` | 分支或标签已创建 | 引用名称、引用类型 |
|
||||
| `delete` | 分支或标签已删除 | 引用名称、引用类型 |
|
||||
| `star` | 仓库加星/取消星标 | 星标数、操作 |
|
||||
| `fork` | 仓库已复刻 | 源 → 目标复刻 |
|
||||
| `pull_request_review` | PR 审查已提交 | 审查状态(已批准/需修改/已评论)、正文 |
|
||||
| `pull_request_review_comment` | 行内代码审查评论 | 文件路径、行号、评论内容 |
|
||||
| `commit_comment` | 提交的评论 | 提交 SHA、评论内容 |
|
||||
| `member` | 协作者添加/移除 | 成员登录名、操作 |
|
||||
| `label` | 标签创建/编辑/删除 | 标签名称、颜色、描述 |
|
||||
| `milestone` | 里程碑打开/关闭 | 进度条、议题计数、截止日期 |
|
||||
| `discussion` | 讨论创建/回答 | 标题、分类、操作 |
|
||||
| `discussion_comment` | 讨论的评论 | 评论内容、讨论引用 |
|
||||
| `repository` | 仓库重命名/转移 | 旧 → 新名称、变更 |
|
||||
| `code_scanning_alert` | 代码扫描告警 | 严重程度、规则 ID、文件路径 |
|
||||
| `dependabot_alert` | Dependabot 告警 | 严重程度、包、受影响版本、修复版本 |
|
||||
| `custom` | 签名的自定义 JSON webhook | 任意 title/description/color/url/author/fields(见[自定义 webhook](../guide/ingress.md#自定义-webhook)) |
|
||||
|
||||
## 颜色编码
|
||||
|
||||
每种事件类型在 Discord 嵌入中使用不同的颜色(来自 `server/lib/formatters/colors.ts`):
|
||||
|
||||
| 颜色 | 事件 |
|
||||
|------------------|---------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 绿色 (`#2da44e`) | push、PR 打开/可审查、issue 打开、工作流成功、发布已发布、检查成功、审查已批准、部署成功、成员添加、里程碑关闭、讨论已回答 |
|
||||
| 红色 (`#f85149`) | PR 关闭、issue 关闭、工作流失败、发布已删除、delete、检查失败、审查请求修改、部署失败、成员移除、代码扫描/Dependabot 严重与高危 |
|
||||
| 紫色 (`#8957e5`) | PR 合并、label、discussion |
|
||||
| 蓝色 (`#1f6feb`) | PR(其他操作)、issue 重新打开、fork、里程碑打开 |
|
||||
| 黄色 (`#d29922`) | 工作流(排队/运行中/其他)、预发布 release、star、检查(其他)、部署待定、代码扫描/Dependabot 中危 |
|
||||
| 灰色 (`#6e7681`) | issue 评论、commit 评论、讨论评论 |
|
||||
| 灰色 (`#8b949e`) | 审查评论、repository、代码扫描/Dependabot 低危、默认 |
|
||||
| 颜色 | 事件 |
|
||||
|--------------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 绿色 (`#2da44e`) | push、PR 打开/可审查、issue 打开、工作流成功、发布已发布、检查成功、审查已批准、部署成功、成员添加、里程碑关闭、讨论已回答 |
|
||||
| 红色 (`#f85149`) | PR 关闭、issue 关闭、工作流失败、发布已删除、delete、检查失败、审查请求修改、部署失败、成员移除、代码扫描/Dependabot 严重与高危 |
|
||||
| 紫色 (`#8957e5`) | PR 合并、label、discussion |
|
||||
| 蓝色 (`#1f6feb`) | PR(其他操作)、issue 重新打开、fork、里程碑打开 |
|
||||
| 黄色 (`#d29922`) | 工作流(排队/运行中/其他)、预发布 release、star、检查(其他)、部署待定、代码扫描/Dependabot 中危 |
|
||||
| 灰色 (`#6e7681`) | issue 评论、commit 评论、讨论评论 |
|
||||
| 灰色 (`#8b949e`) | 审查评论、repository、代码扫描/Dependabot 低危、默认 |
|
||||
|
||||
## 通用回退
|
||||
|
||||
|
|
@ -66,11 +66,11 @@ WebHooker 支持 28 种 GitHub webhook 事件类型,每种都有专用的格
|
|||
|
||||
实操指南见[过滤器教程](../guide/filters),包含完整示例。
|
||||
|
||||
| 过滤器 | 适用事件 |
|
||||
|-----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `event` | 所有事件 |
|
||||
| `repo` | 所有事件 |
|
||||
| `actor` | 所有事件 |
|
||||
| `action` | 载荷中包含 `action` 字段的事件 |
|
||||
| `branch` | push、pull_request、pull_request_review、pull_request_review_comment、create、delete、workflow_run、workflow_job、check_suite、deployment、code_scanning_alert |
|
||||
| `keyword` | 所有事件(搜索完整载荷正文) |
|
||||
| 过滤器 | 适用事件 |
|
||||
|-------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `event` | 所有事件 |
|
||||
| `repo` | 所有事件 |
|
||||
| `actor` | 所有事件 |
|
||||
| `action` | 载荷中包含 `action` 字段的事件 |
|
||||
| `branch` | push、pull_request、pull_request_review、pull_request_review_comment、create、delete、workflow_run、workflow_job、check_suite、deployment、code_scanning_alert |
|
||||
| `keyword` | 所有事件(搜索完整载荷正文) |
|
||||
|
|
|
|||
|
|
@ -1,19 +1,29 @@
|
|||
# 配置
|
||||
|
||||
本页是密钥与 Web 控制台的参考。核心概念在独立页面中说明:
|
||||
|
||||
| 主题 | 页面 |
|
||||
|--------------------------------------------------|----------------------------------------------------------------------|
|
||||
| 路由、目标、`fallback` / `stop`、身份组提醒 | [路由与目标](./routes) |
|
||||
| 分组、角色、邀请、自助注册、日志频道 | [分组与访问控制](./groups) |
|
||||
| Webhook 提供方、分组入口、自定义 webhook | [Webhook 接入与租户隔离](./ingress) |
|
||||
| KV / D1 键布局 | [存储布局](./storage) |
|
||||
| 过滤器(模式语法参考) | 下方[过滤器类型](#过滤器类型) / [过滤器教程](./filters) |
|
||||
|
||||
## 密钥
|
||||
|
||||
WebHooker 需要多个密钥才能运行。本地开发时存储在 `.dev.vars` 中,生产环境使用 Cloudflare Worker Secrets。
|
||||
WebHooker 的运行需要若干密钥。本地开发时放入 `.dev.vars`,生产环境使用 Cloudflare Worker Secrets。
|
||||
|
||||
### 必需密钥
|
||||
|
||||
| 变量 | 说明 |
|
||||
|-------------------------|----------------------------------------------------------|
|
||||
| `GITHUB_WEBHOOK_SECRET` | GitHub App 设置中的 Webhook 密钥 |
|
||||
| `GITEA_WEBHOOK_SECRET` | Gitea 实例的 Webhook 密钥(仅接收 Gitea webhook 时需要) |
|
||||
| `GITHUB_CLIENT_ID` | App 设置中的 OAuth 客户端 ID |
|
||||
| `GITHUB_CLIENT_SECRET` | App 设置中的 OAuth 客户端密钥 |
|
||||
| `DISCORD_TOKEN` | Discord Bot Token |
|
||||
| `TELEGRAM_TOKEN` | Telegram Bot Token(BotFather 获取)—— Telegram 路由必需 |
|
||||
| 变量 | 说明 |
|
||||
|-------------------------|-------------------------------------------------------------------|
|
||||
| `GITHUB_WEBHOOK_SECRET` | GitHub App 设置中的 webhook 密钥 |
|
||||
| `GITEA_WEBHOOK_SECRET` | Gitea 实例的 webhook 密钥(仅接收 Gitea webhook 时需要) |
|
||||
| `GITHUB_CLIENT_ID` | App 设置中的 OAuth 客户端 ID |
|
||||
| `GITHUB_CLIENT_SECRET` | App 设置中的 OAuth 客户端密钥 |
|
||||
| `DISCORD_TOKEN` | Discord 机器人 Token |
|
||||
| `TELEGRAM_TOKEN` | Telegram 机器人 Token(BotFather 获取)—— Telegram 路由必需 |
|
||||
|
||||
> [!NOTE]
|
||||
> `GITHUB_APP_ID` 与 `GITHUB_PRIVATE_KEY`(PKCS#8 PEM)用于 GitHub App **安装流程**
|
||||
|
|
@ -25,291 +35,44 @@ WebHooker 需要多个密钥才能运行。本地开发时存储在 `.dev.vars`
|
|||
|
||||
| 变量 | 说明 | 默认值 |
|
||||
|-----------------------------|--------------------------------------------------------------------------------------------------|-------------------------|
|
||||
| `BASE_URL` | OAuth 回调的公开 URL | `http://localhost:8787` |
|
||||
| `DISCORD_PUBLIC_KEY` | Discord 应用的公钥(开发者门户获取),交互功能必需 | 未设置时交互返回 401 |
|
||||
| `DISCORD_APPLICATION_ID` | Discord 应用 ID;省略时自动获取 | 自动获取 |
|
||||
| `TELEGRAM_WEBHOOK_SECRET` | `POST /telegram/webhook` 验签密钥(X-Telegram-Bot-Api-Secret-Token) | 未设置时不校验 |
|
||||
| `TELEGRAM_RICH_HEADER_HOST` | 外部 rich-header 服务的基础 URL;未设置时使用内置 `GET /api/richheader` 提供 Telegram 头像卡片 | 内置 `/api/richheader` |
|
||||
| `BASE_URL` | OAuth 回调的公共 URL | `http://localhost:8787` |
|
||||
| `ADMIN_USER_IDS` | 允许访问 WebUI 的 GitHub 用户 ID(或登录名),逗号分隔 | 未设置时 WebUI 关闭 |
|
||||
| `ALLOW_SELF_SIGNUP` | 开启(`1`/`true`)后,没有任何分组权限的 GitHub 用户首次登录会自动获得个人分组而非 403 | 关闭 |
|
||||
| `AUDIT_RETENTION_DAYS` | 定时清理时审计日志的保留天数 | `90` |
|
||||
| `NUXT_PUBLIC_DOCS_URL` | 落地页使用的文档站 URL(客户端运行时配置) | 落地页默认值 |
|
||||
| `NUXT_PUBLIC_REPO_URL` | 落地页使用的 GitHub 仓库 URL | 落地页默认值 |
|
||||
| `NUXT_PUBLIC_LEGAL_CONTACT` | `/terms` 与 `/privacy` 页面展示的联系方式 | 未设置时显示占位文本 |
|
||||
| `DISCORD_PUBLIC_KEY` | Discord 应用的公钥(开发者门户获取),交互功能必需 | 未设置时交互返回 401 |
|
||||
| `DISCORD_APPLICATION_ID` | Discord 应用 ID;省略时自动获取 | 自动获取 |
|
||||
| `TELEGRAM_WEBHOOK_SECRET` | `POST /telegram/webhook` 验签密钥(X-Telegram-Bot-Api-Secret-Token) | 未设置时不校验 |
|
||||
| `TELEGRAM_RICH_HEADER_HOST` | 外部 rich-header 服务的基础 URL;未设置时使用内置的 `GET /api/richheader` 生成 Telegram 头像卡片 | 内置 `/api/richheader` |
|
||||
|
||||
## Webhook 提供方
|
||||
|
||||
WebHooker 通过同一个 `POST /webhook` 端点接收多个 forge 的 webhook,按请求头自动识别来源;只需把各 forge 的 webhook 指向 `{BASE_URL}/webhook` 即可。
|
||||
|
||||
| 提供方 | 事件请求头 | 签名请求头 | 签名格式 | 密钥 |
|
||||
|--------|------------------|-----------------------|----------------------------|-------------------------|
|
||||
| GitHub | `X-GitHub-Event` | `X-Hub-Signature-256` | `sha256=<hex>` HMAC-SHA256 | `GITHUB_WEBHOOK_SECRET` |
|
||||
| Gitea | `X-Gitea-Event` | `X-Gitea-Signature` | 纯 hex HMAC-SHA256 | `GITEA_WEBHOOK_SECRET` |
|
||||
|
||||
投递 id 去重使用 `X-GitHub-Delivery`(GitHub)或 `X-Gitea-Delivery`(Gitea)请求头(存在时)。
|
||||
|
||||
Gitea payload 会被归一化为与 GitHub 相同的内部结构,因此路由、过滤器与 28 个格式化器无需改动即可复用;未知或未映射的 Gitea 事件回退到通用格式化器。仓库/提交/用户链接基于 payload 的 `repository.html_url` 生成,会指向你的 Gitea 实例。
|
||||
|
||||
## Web 控制台
|
||||
|
||||
WebHooker 内置了位于 `/admin` 的配置控制台,可在浏览器中管理路由。它由 GitHub OAuth 和管理员白名单保护。
|
||||
WebHooker 在 `/admin` 提供内置配置控制台,可在浏览器中管理路由、分组、成员、邀请、发送日志与审计日志。它由 GitHub OAuth 与管理员白名单保护。
|
||||
|
||||
### 设置
|
||||
|
||||
1. 配置 `ADMIN_USER_IDS`,填写允许管理一切的 GitHub 用户 ID,也支持登录名,例如 `ADMIN_USER_IDS=12345,RhenCloud`。未设置时控制台禁用(除非开启 `ALLOW_SELF_SIGNUP`)。
|
||||
2. 打开 `/admin` 并使用 GitHub 登录。
|
||||
3. 没有任何权限的用户收到 `403`,除非开启 `ALLOW_SELF_SIGNUP=1`(自动获得个人分组)或通过分组[邀请链接](#邀请)加入。
|
||||
3. 没有任何访问权限的用户会得到 `403`,除非 `ALLOW_SELF_SIGNUP=1`(获得个人分组)或跟随分组[邀请链接](./groups#邀请)。
|
||||
|
||||
### 端点
|
||||
控制台以 SPA 形式在 `/admin` 提供;其标签页可通过 URL 路径直达(`/admin/groups`、`/admin/logs`、`/admin/audit`)。`/admin` 之外未匹配到端点的 URL 直接返回 `404`,而不会展示控制台。
|
||||
|
||||
控制台以 SPA 形式挂在 `/admin`,各标签页可通过 URL 路径直达(`/admin/groups`、`/admin/logs`、`/admin/audit`)。`/admin` 之外且未匹配下方端点的 URL 直接返回 `404`,不会再被吞进控制台。
|
||||
|
||||
| 端点 | 说明 |
|
||||
|-------------------------------------------------|----------------------------------------------------------|
|
||||
| `GET /admin` | 配置控制台页面 |
|
||||
| `GET /admin/login` | 开始 GitHub OAuth 登录 |
|
||||
| `GET /admin/logout` | 销毁会话 |
|
||||
| `GET /admin/invite?token=…` | 接受分组邀请(浏览器页面) |
|
||||
| `GET /admin/api/me` | 当前会话、权限范围、分组和角色 |
|
||||
| `GET /admin/api/routes` | 列出路由(按权限过滤) |
|
||||
| `PUT /admin/api/routes` | 替换路由(按分组 owner/admin 权限) |
|
||||
| `GET /admin/api/groups` | 列出分组 + 当前用户在各组的角色 |
|
||||
| `PUT /admin/api/groups` | 替换分组(超管全量;owner 仅自己的组) |
|
||||
| `GET /admin/api/groups/:id/routes` | 列出某分组的路由 |
|
||||
| `PUT /admin/api/groups/:id/routes` | 替换某分组的路由(owner/admin) |
|
||||
| `PUT /admin/api/groups/:id/rename` | 重命名分组(owner);路由、webhook secret 与邀请自动跟随 |
|
||||
| `GET /admin/api/logs` | 发送日志(按可访问路由过滤) |
|
||||
| `GET /admin/api/logs/:id` | 单条发送日志(按权限过滤) |
|
||||
| `POST /admin/api/groups/:id/invites` | 创建邀请链接(owner) |
|
||||
| `GET /admin/api/groups/:id/invites` | 列出待接受邀请(owner) |
|
||||
| `DELETE /admin/api/invites/:token` | 撤销邀请(owner) |
|
||||
| `GET /admin/api/audit` | 审计日志(按可访问分组过滤) |
|
||||
| `GET /admin/api/groups/:id/webhook` | 分组 webhook 入口信息(owner) |
|
||||
| `POST /admin/api/groups/:id/webhook/regenerate` | 生成/重新生成分组 webhook secret(owner) |
|
||||
| `DELETE /admin/api/groups/:id/webhook` | 停用分组 webhook 入口(owner) |
|
||||
|
||||
控制台支持新增、编辑、删除和开关路由。保存后立即写入 KV `config:routes` 并使配置缓存失效,下一次 webhook 处理即会生效。上限:每个实例最多 **200 条路由** 与 **100 个分组**。
|
||||
|
||||
## Webhook 端点
|
||||
|
||||
### 全局端点(`POST /webhook`)
|
||||
|
||||
旧版全局端点使用运维者的全局 secret(`GITHUB_WEBHOOK_SECRET`、`GITEA_WEBHOOK_SECRET`)验签,可分发到**所有**路由。GitHub App 安装事件从该端点进入;多租户场景请用分组的 `installationId` 做隔离。
|
||||
|
||||
### 分组端点(`POST /webhook/{groupId}`)
|
||||
|
||||
每个分组可以启用独立的 webhook 入口和 secret(在分组页面「Webhook 入口」面板生成,owner 权限)。载荷使用**分组的** secret 验签,且只有该分组的路由会触发。SaaS 用户可以借此配置 Gitea、classic GitHub 或自定义 webhook,无需共享(也无需知道)运维者的全局 secret。
|
||||
|
||||
- 支持所有 provider:GitHub(`X-Hub-Signature-256`)、Gitea(`X-Gitea-Signature`)、自定义(`X-WebHooker-Signature`)
|
||||
- secret 为 64 位十六进制字符串;重新生成后旧值立即失效
|
||||
- 去重 key 按租户隔离(`delivery:{groupId}:{id}`)
|
||||
- 分组未配置 secret(或分组不存在)时返回 `404`
|
||||
|
||||
### 自定义 Webhook
|
||||
|
||||
向 `POST /webhook/{groupId}`(或全局端点)POST 任意 JSON,并用分组的 secret 对原始 body 计算 HMAC-SHA256 放在 `X-WebHooker-Signature: sha256=<hex>` 头中。载荷会变成 `custom` 事件走标准路由管线——创建一条 `event: custom` 的路由(控制台有模板)即可分发到该路由的目标,并自动记录 `send_logs`、出现在分组的日志频道。
|
||||
|
||||
载荷格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Deploy failed",
|
||||
"description": "Prod rollout failed at 12:03 UTC",
|
||||
"color": "red",
|
||||
"url": "https://ci.example.com/runs/42",
|
||||
"repo": "acme/widget",
|
||||
"author": {
|
||||
"name": "alice",
|
||||
"iconUrl": "https://…/alice.png",
|
||||
"url": "https://github.com/alice"
|
||||
},
|
||||
"fields": [{ "name": "Env", "value": "prod", "inline": true }],
|
||||
"footer": "my-monitor",
|
||||
"deliveryId": "alert-123"
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---------------|----------|----------------------------------------------------------------------------------------------------------|
|
||||
| `title` | string | 消息标题(缺失时回退为「自定义消息」) |
|
||||
| `description` | string | 可选的消息正文 |
|
||||
| `color` | string | 可选消息颜色:颜色词(`red`、`green`、`yellow`、`blue`、`purple`、`orange`、`cyan`、`gray`)或 `#rrggbb` |
|
||||
| `url` | string | 可选标题链接 |
|
||||
| `repo` | string | 可选 `owner/repo`;会加在标题前并作为 footer |
|
||||
| `author` | object | 可选的 `{ name, iconUrl, url }` |
|
||||
| `fields` | object[] | 可选的嵌入字段 `{ name, value, inline }` |
|
||||
| `footer` | string | 可选的 footer 覆盖 |
|
||||
| `deliveryId` | string | 可选的发送方去重 id(重试场景) |
|
||||
|
||||
### GitHub App 租户隔离
|
||||
|
||||
GitHub App 安装后,**所有**安装方的事件都会到达全局端点。要让租户互相隔离,请把每个分组绑定到应当为其提供事件的安装 ID:`"installationId": 12345678`。该 ID 可从 App 安装 webhook 载荷(`installation.id`)或 GitHub App 安装页 URL 看到。即使分组的 `owners` 为空,来自其它安装的事件也会被拒绝。未设置 `installationId` 的分组保持旧行为(`owners` 过滤)。
|
||||
|
||||
绑定是**自动配置**的 —— 将 GitHub App 的 _Setup URL_ 指向 `{BASE_URL}/auth/github/install`。用户安装 App 后浏览器立即跳转到该页面(页面需要已登录的管理员会话——未登录用户会先被重定向走 OAuth 流程),可选择将安装绑定到:**新分组**(`inst-{installationId}`,默认)或任意**自己拥有 owner 权限的已有分组**(提交时再次校验角色;由 `POST /auth/github/install/bind` 完成配置)。无需手动填写 ID。作为兜底(例如未配置 Setup URL 时),`installation.created` webhook 事件也会自动创建/绑定分组 —— `owners` 匹配安装账号的现有分组会被绑定,否则创建独立的 `inst-{installationId}` 分组。之后在控制台为分组添加路由和成员即可。
|
||||
|
||||
## 路由
|
||||
|
||||
路由定义了哪些事件被转发到哪些频道(Discord 或 Telegram)。它们以 JSON 数组形式存储在 Cloudflare KV 中,键为 `config:routes`。
|
||||
|
||||
**没有默认路由**——每条路由必须自行定义目标频道。若未配置任何路由,则不会转发任何事件。
|
||||
|
||||
### 路由模式
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "unique-route-id",
|
||||
"name": "可读名称",
|
||||
"enabled": true,
|
||||
"groupId": "my-group",
|
||||
"fallback": false,
|
||||
"stop": false,
|
||||
"discordRoleIds": ["111111111111111111"],
|
||||
"filters": [
|
||||
{ "type": "event", "match": "push" },
|
||||
{ "type": "repo", "match": "org/repo", "exclude": false }
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"platform": "discord",
|
||||
"channelId": "必填频道ID",
|
||||
"threadId": "可选线程ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`targets` 数组的每一项是一个推送目标,因此一条路由可同时转发到多个频道(例如同时发到 Discord 频道 **和** Telegram 群组)。`target.platform` 选择推送目标:`discord`(默认)或 `telegram`。**Discord** 需 `target.channelId`(`target.threadId` 可选的子区);**Telegram** 需 `target.chatId`(群组/超级群组聊天 id,如 `-1001234567890`),`target.topicId`(话题的 `message_thread_id`,相当于 Discord 的子区)可选。不存在默认频道回退。
|
||||
|
||||
### Discord 身份组提醒
|
||||
|
||||
在路由上设置 `discordRoleIds`,当该路由触发时会 @提醒(ping)一个或多个 Discord 身份组。`<@&roleId>` 形式的提醒会拼接到该路由所有 **Discord** 目标的消息正文开头;Telegram 目标会忽略此字段。只有在机器人拥有 `Mention Everyone` 权限(或该身份组被标记为可被提及 mentionable)且机器人能看到该身份组时,提醒才会真正触发通知。
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "release-notify",
|
||||
"name": "发布时提醒",
|
||||
"enabled": true,
|
||||
"groupId": "default",
|
||||
"discordRoleIds": ["111111111111111111", "222222222222222222"],
|
||||
"filters": [{ "type": "event", "match": "release" }],
|
||||
"targets": [{ "platform": "discord", "channelId": "必填频道ID" }]
|
||||
}
|
||||
```
|
||||
|
||||
也可以在管理控制台的“Discord 身份组提醒”中配置。
|
||||
|
||||
其他路由字段:
|
||||
|
||||
| 字段 | 类型 | 必需 | 说明 |
|
||||
|------------------|----------|------|------------------------------------------------------------------------|
|
||||
| `groupId` | string | 是 | 该路由所属[分组](#分组)的 id |
|
||||
| `fallback` | boolean | 否 | 为 `true` 时,仅当没有其它路由匹配该事件时才发送,其自身过滤器会被忽略 |
|
||||
| `stop` | boolean | 否 | 为 `true` 且该路由匹配时,停止评估后续路由 |
|
||||
| `discordRoleIds` | string[] | 否 | 该路由触发时要在 Discord 目标中 @提醒的身份组 id |
|
||||
|
||||
### 自定义路由示例
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "backend-prs",
|
||||
"name": "后端 PR",
|
||||
"enabled": true,
|
||||
"groupId": "backend-team",
|
||||
"filters": [
|
||||
{ "type": "repo", "match": "myorg/backend" },
|
||||
{ "type": "event", "match": "pull_request" },
|
||||
{ "type": "actor", "match": "[bot]", "exclude": true }
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"platform": "telegram",
|
||||
"chatId": "-1001234567890",
|
||||
"topicId": "9876543210"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## 分组
|
||||
|
||||
路由隶属于分组。分组用于限定管理权限,并可限制哪些事件允许流入。它们以 JSON 数组形式存储在 Cloudflare KV 中,键为 `config:groups`。
|
||||
|
||||
### 分组模式
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "backend-team",
|
||||
"name": "后端团队",
|
||||
"members": [
|
||||
{ "login": "rhencloud", "role": "owner" },
|
||||
{ "login": "octobot", "role": "admin" },
|
||||
{ "login": "reader", "role": "viewer" }
|
||||
],
|
||||
"owners": ["myorg"],
|
||||
"providers": ["github", "gitea"],
|
||||
"installationId": 12345678,
|
||||
"logTarget": { "platform": "discord", "channelId": "123456789", "threadId": "987654321" }
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必需 | 说明 |
|
||||
|------------------|----------|------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `id` | string | 是 | 小写 id(`a-z0-9`、`-`),由每条路由的 `groupId` 引用。可修改:重命名分组会同步更新其路由、分组级 webhook secret 与待接受邀请 |
|
||||
| `name` | string | 是 | 可读的分组名称 |
|
||||
| `members` | object[] | 否 | `{ login, role }` 列表;角色为 `owner`、`admin` 或 `viewer` |
|
||||
| `adminIds` | string[] | 否 | 已废弃的旧字段;存在时按 role 为 `owner` 的成员处理 |
|
||||
| `owners` | string[] | 否 | 允许事件进入该分组的组织/用户登录名;为空表示不限制 |
|
||||
| `providers` | string[] | 否 | 允许进入该分组的来源平台(`github`、`gitea`);为空表示全部 |
|
||||
| `installationId` | number | 否 | 绑定到该分组的 GitHub App 安装 ID;只接受该安装的事件(为空表示全部) |
|
||||
| `emoji` | boolean | 否 | 是否在该分组消息中显示 emoji(默认 `true`) |
|
||||
| `lang` | string | 否 | 该分组所有路由的消息语言(如 `en`、`zh`;可通过 KV `i18n:<lang>` 自定义)——默认 `en` |
|
||||
| `logTarget` | object | 否 | Webhook 日志频道:Discord 目标 `{ platform, channelId, threadId? }` 或 Telegram 目标 `{ platform, chatId, topicId? }`,本分组路由每次投递 webhook 时都会向其发送摘要 |
|
||||
|
||||
### 角色
|
||||
|
||||
每个分组成员拥有三种角色之一。超级管理员(`ADMIN_USER_IDS`)始终绕过角色限制。
|
||||
|
||||
| 角色 | 查看路由/日志 | 编辑路由 | 管理成员与邀请 | 编辑分组设置 |
|
||||
|----------|---------------|----------|----------------|--------------------|
|
||||
| `owner` | ✓ | ✓ | ✓ | ✓(`owners` 除外) |
|
||||
| `admin` | ✓ | ✓ | ✗ | ✗ |
|
||||
| `viewer` | ✓(只读) | ✗ | ✗ | ✗ |
|
||||
|
||||
### 权限模型
|
||||
|
||||
- **超级管理员**(`ADMIN_USER_IDS`)可查看和编辑所有分组及全部路由;只有他们能修改分组的 `owners` 列表。
|
||||
- **owner** 管理本组的路由、成员、邀请、名称、id、`emoji` 与 `providers`;不能移除最后一位 owner,也没有其他 owner 时不能把自己降级。
|
||||
- **admin** 可编辑本组路由并查看日志;**viewer** 只读控制台。
|
||||
- 分组管理端点通过 `/admin/api/groups/:id/routes` 一次只操作一个分组;`groupId` 由路径参数强制指定。
|
||||
- `owners` 列表限定哪些事件参与者(发送者登录名)的事件会被该分组的路由投递。
|
||||
- `providers` 列表限定哪个 forge(`github`、`gitea`)的事件会被该分组的路由投递。即使组织/用户同名,也可以借此将 GitHub 与 Gitea 分组区分开。
|
||||
|
||||
### Webhook 日志频道
|
||||
|
||||
分组可以设置 `logTarget` 指向一个 Discord 频道/子区或 Telegram 群组/话题。每当该分组的路由分发(dispatch)一个 webhook,就会向那里发送一条摘要消息:事件类型/动作、仓库、投递 ID,以及每条「路由 × 目标」一行的 ✅/❌ 结果(失败时附带错误信息;最多列出前 10 行,其余以 `+N` 汇总)。全部成功时消息为绿色,任一失败则为红色。摘要使用分组的消息语言。日志消息尽力发送,本身不会被记入 D1 发送日志。
|
||||
|
||||
### 邀请
|
||||
|
||||
owner(及超级管理员)可在分组的「成员」面板创建一次性邀请链接,7 天内有效。接受邀请后用户以邀请角色(`admin` 或 `viewer`,绝不授予 `owner`)加入;已有的 `viewer` 会被升级为 `admin`。邀请存储在 KV `invite:{token}`。
|
||||
|
||||
### 自助注册
|
||||
|
||||
开启 `ALLOW_SELF_SIGNUP=1` 后,没有分组权限的 GitHub 用户首次登录会获得一个由自己担任 owner 的个人分组(`u-{userId}`),而不是 `403`。这是全自助 SaaS 部署的入口;关闭它则控制台保持仅邀请制。
|
||||
所有管理端点(`/admin/api/*`)见 [Admin API](../api/admin)。保存的路由会立即写入 KV `config:routes` 并使配置缓存失效,下一次 webhook 处理即会生效。
|
||||
|
||||
## 过滤器类型
|
||||
|
||||
实操指南见[过滤器教程](./filters),包含完整示例。
|
||||
|
||||
| 类型 | 匹配对象 | 示例 |
|
||||
|-----------|------------------|-------------------------------------------|
|
||||
| `event` | GitHub 事件名称 | `push`, `pull_*`, `pull_request` |
|
||||
| `repo` | 仓库全名 | `org/repo`, `org/*` |
|
||||
| `actor` | 发送者登录名 | `username`, `[bot]`, `*[bot]` |
|
||||
| `action` | 事件操作 | `opened`, `closed`, `published` |
|
||||
| `branch` | 分支名称 | `main`, `feature-?`, `/^release-/` |
|
||||
| `keyword` | 载荷正文中的文本 | `deploy`, `/fix\s+\d+/` |
|
||||
| 类型 | 匹配对象 | 示例 |
|
||||
|-----------|------------------|--------------------------------------|
|
||||
| `event` | GitHub 事件名称 | `push`, `pull_*`, `pull_request` |
|
||||
| `repo` | 仓库全名 | `org/repo`, `org/*` |
|
||||
| `actor` | 发送者登录名 | `username`, `[bot]`, `*[bot]` |
|
||||
| `action` | 事件操作 | `opened`, `closed`, `published` |
|
||||
| `branch` | 分支名称 | `main`, `feature-?`, `/^release-/` |
|
||||
| `keyword` | 载荷正文中的文本 | `deploy`, `/fix\s+\d+/` |
|
||||
|
||||
### 过滤器行为
|
||||
|
||||
|
|
@ -328,37 +91,3 @@ owner(及超级管理员)可在分组的「成员」面板创建一次性邀
|
|||
{ "type": "event", "match": "push" }
|
||||
{ "type": "event", "match": ["push", "pull_request"] }
|
||||
```
|
||||
|
||||
## 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 有效期 |
|
||||
| `state:{hex}` | `{ redirectTo, expiresAt, discordUserId?, telegramUserId?, telegramChatId? }` | 600 秒 |
|
||||
| `invite:{token}` | `{ groupId, role, expiresAt, createdBy, note? }` | 7 天 |
|
||||
| `invite:group:{id}` | 每组的 Token 索引(保证邀请列表一致性) | 永久 |
|
||||
| `delivery:{id}` | Webhook 投递 id(去重标记) | 300 秒 |
|
||||
| `delivery:{groupId}:{id}` | 分组级 webhook 入口的租户级投递去重 | 300 秒 |
|
||||
| `tenant:{groupId}` | 分组 webhook secret(64 位 hex,控制台生成) | 永久 |
|
||||
| `msg:{routeId}:{key}:{target}` | 原地更新用消息 id 追踪(如 `workflow_run` / `check_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、事件、目标、成功/失败、耗时、错误码、详情) |
|
||||
| `audit_logs` | 每次管理操作一行(登录/登出、分组/路由/成员/邀请变更) |
|
||||
| `discord_links` | 映射 `discord_user_id` → `github_user_id`,用于 Discord `/gh` 命令 |
|
||||
| `telegram_links` | 映射 `telegram_user_id` → `github_user_id`,用于 Telegram `/gh` 命令 |
|
||||
|
||||
`audit_logs` 由定时触发器按 `AUDIT_RETENTION_DAYS`(默认 90)自动清理。
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
## 如何让分组使用自己的 webhook 端点?
|
||||
|
||||
见[分组端点](./configuration#分组端点)——在分组的 **Webhook 端点**面板(owner 角色)生成密钥,然后用 `POST /webhook/{groupId}` 与分组密钥发送。
|
||||
见[分组端点](./ingress#分组端点)——在分组的 **Webhook 端点**面板(owner 角色)生成密钥,然后用 `POST /webhook/{groupId}` 与分组密钥发送。
|
||||
|
||||
## 可以脱离 Cloudflare Workers 运行吗?
|
||||
|
||||
|
|
@ -34,4 +34,4 @@
|
|||
|
||||
## 数据存储在哪里?
|
||||
|
||||
配置存于 Cloudflare KV(`config:routes`、`config:groups`);发送/审计日志与平台↔GitHub 绑定存于 D1。见[存储布局](./configuration#kv-存储布局)。
|
||||
配置存于 Cloudflare KV(`config:routes`、`config:groups`);发送/审计日志与平台↔GitHub 绑定存于 D1。见[存储布局](./storage#kv-存储布局)。
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# 过滤器教程
|
||||
|
||||
过滤器决定哪些 Webhook 事件会被[路由](./configuration#路由)转发。只有当路由 `filters` 数组中的**每一个**过滤器都匹配时,路由才会触发(AND 逻辑)。本页是一份上手教程:解释每种过滤器类型的行为,以及如何组合它们实现真实场景的路由规则。
|
||||
过滤器决定哪些 Webhook 事件会被[路由](./routes)转发。只有当路由 `filters` 数组中的**每一个**过滤器都匹配时,路由才会触发(AND 逻辑)。本页是一份上手教程:解释每种过滤器类型的行为,以及如何组合它们实现真实场景的路由规则。
|
||||
|
||||
参考表格见配置指南的[过滤器类型](./configuration#过滤器类型),完整事件列表见[支持的事件](../events/supported)。
|
||||
|
||||
|
|
|
|||
65
docs/zh/guide/groups.md
Normal file
65
docs/zh/guide/groups.md
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# 分组与访问控制
|
||||
|
||||
路由归属于分组。分组用于划分管理权限,并可限制进入其中的事件。它们以 JSON 数组形式存储在 Cloudflare KV 的 `config:groups` 键下,可通过 [Web 控制台](./configuration#web-控制台)或 [Admin API](../api/admin) 管理。每个实例最多可保存 **100 个分组**。
|
||||
|
||||
## 分组模式
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "backend-team",
|
||||
"name": "Backend Team",
|
||||
"members": [
|
||||
{ "login": "rhencloud", "role": "owner" },
|
||||
{ "login": "octobot", "role": "admin" },
|
||||
{ "login": "reader", "role": "viewer" }
|
||||
],
|
||||
"owners": ["myorg"],
|
||||
"providers": ["github", "gitea"],
|
||||
"installationId": 12345678,
|
||||
"logTarget": { "platform": "discord", "channelId": "123456789", "threadId": "987654321" }
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必需 | 说明 |
|
||||
|------------------|----------|------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `id` | string | 是 | 小写 id(`a-z0-9`、`-`);被每条路由的 `groupId` 引用。可编辑:重命名分组会同步其路由、分组 webhook secret 与待处理邀请 |
|
||||
| `name` | string | 是 | 人类可读的分组名 |
|
||||
| `members` | object[] | 否 | `{ login, role }` 条目;角色为 `owner`、`admin` 或 `viewer` |
|
||||
| `adminIds` | string[] | 否 | 已废弃的旧字段;存在时视为角色为 `owner` 的 `members` |
|
||||
| `owners` | string[] | 否 | 允许进入该分组的事件所属组织/用户登录名;空 = 全部 |
|
||||
| `providers` | string[] | 否 | 允许进入该分组的来源平台(`github`、`gitea`);空 = 全部 |
|
||||
| `installationId` | number | 否 | 绑定到该分组的 GitHub App 安装 id;仅接受该安装的事件(空 = 全部) |
|
||||
| `emoji` | boolean | 否 | 该分组消息是否包含表情(默认 `true`) |
|
||||
| `lang` | string | 否 | 该分组所有路由的消息语言(如 `en`、`zh`;可通过 KV `i18n:<lang>` 自定义)——见[消息语言](./i18n)——默认 `en` |
|
||||
| `logTarget` | object | 否 | Webhook 日志频道:Discord 目标 `{ platform, channelId, threadId? }` 或 Telegram 目标 `{ platform, chatId, topicId? }`,接收该分组路由每次分发 webhook 的摘要 |
|
||||
|
||||
## 角色
|
||||
|
||||
每个分组成员拥有三种角色之一。超级管理员(`ADMIN_USER_IDS`)始终绕过这些限制。
|
||||
|
||||
| 角色 | 查看路由/日志 | 编辑路由 | 管理成员与邀请 | 编辑分组设置 |
|
||||
|----------|---------------|----------|----------------|------------------|
|
||||
| `owner` | ✓ | ✓ | ✓ | ✓(除 `owners`) |
|
||||
| `admin` | ✓ | ✓ | ✗ | ✗ |
|
||||
| `viewer` | ✓(只读) | ✗ | ✗ | ✗ |
|
||||
|
||||
## 权限模型
|
||||
|
||||
- **超级管理员**(`ADMIN_USER_IDS`)可查看和编辑所有分组与全部路由;只有他们能编辑分组的 `owners` 列表。
|
||||
- **Owner** 管理自己分组的路由、成员、邀请、名称、id、`emoji` 与 `providers`。不能移除最后一个 owner,也不能在没有其他 owner 时降级自己。
|
||||
- **Admin** 编辑自己分组内的路由并查看日志;**viewer** 只有只读控制台。
|
||||
- 分组管理端点通过 `/admin/api/groups/:id/routes` 一次操作一个分组;`groupId` 强制取自路径参数。
|
||||
- `owners` 列表限制该分组路由究竟会分发哪些事件操作者(发送者登录名)的事件。
|
||||
- `providers` 列表限制该分组路由会分发哪个 forge(`github`、`gitea`)的事件。即使组织/用户名冲突,也可借此将 GitHub 与 Gitea 分组分开。
|
||||
|
||||
## Webhook 日志频道
|
||||
|
||||
分组可以设置 `logTarget` 指向一个 Discord 频道/子区或 Telegram 群组/话题。每当该分组的路由分发(dispatch)一个 webhook,就会向那里发送一条摘要消息:事件类型/动作、仓库、投递 ID,以及每条「路由 × 目标」一行的 ✅/❌ 结果(失败时附带错误信息;最多列出前 10 行,其余以 `+N` 汇总)。全部成功时消息为绿色,任一失败则为红色。摘要使用分组的消息语言。日志消息尽力发送,本身不会被记入 D1 发送日志。
|
||||
|
||||
## 邀请
|
||||
|
||||
Owner(与超级管理员)可以在分组的 _成员_ 面板创建单次使用、有效期 7 天的邀请链接。接受邀请后,用户以被邀请的角色(`admin` 或 `viewer`——绝不会是 `owner`)加入;已有 `viewer` 会被升级为 `admin`。邀请存储在 KV 的 `invite:{token}` 键下。
|
||||
|
||||
## 自助注册
|
||||
|
||||
设置 `ALLOW_SELF_SIGNUP=1` 后,没有分组权限的 GitHub 用户首次登录时会获得个人分组(`u-{userId}`,归其所有),而不是 `403`。这是完全自助式 SaaS 安装的入口;关闭它可保持控制台仅邀请制。
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
## 分组语言
|
||||
|
||||
设置 `Group.lang`(如 `"zh"`)可为分组内所有路由选择消息语言——见[分组 → 分组模式](./configuration#分组模式)。分组的 webhook 日志频道摘要使用相同的语言。
|
||||
设置 `Group.lang`(如 `"zh"`)可为分组内所有路由选择消息语言——见[分组 → 分组模式](./groups#分组模式)。分组的 webhook 日志频道摘要使用相同的语言。
|
||||
|
||||
## 自定义覆盖
|
||||
|
||||
|
|
|
|||
71
docs/zh/guide/ingress.md
Normal file
71
docs/zh/guide/ingress.md
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# Webhook 接入与租户隔离
|
||||
|
||||
## Webhook 提供方
|
||||
|
||||
WebHooker 通过同一个 `POST /webhook` 端点接收多个 forge 的 webhook,按请求头自动识别来源;只需把各 forge 的 webhook 指向 `{BASE_URL}/webhook` 即可。
|
||||
|
||||
| 提供方 | 事件请求头 | 签名请求头 | 签名格式 | 密钥 |
|
||||
|--------|------------------|-----------------------|----------------------------|-------------------------|
|
||||
| GitHub | `X-GitHub-Event` | `X-Hub-Signature-256` | `sha256=<hex>` HMAC-SHA256 | `GITHUB_WEBHOOK_SECRET` |
|
||||
| Gitea | `X-Gitea-Event` | `X-Gitea-Signature` | 纯 hex HMAC-SHA256 | `GITEA_WEBHOOK_SECRET` |
|
||||
|
||||
投递 id 去重使用 `X-GitHub-Delivery`(GitHub)或 `X-Gitea-Delivery`(Gitea)请求头(存在时)。
|
||||
|
||||
Gitea 载荷会被归一化为与 GitHub 事件相同的内部结构,因此路由、过滤器与 28 个格式化器无需改动即可工作。未知或未映射的 Gitea 事件回退到通用格式化器。仓库/提交/用户链接取自载荷中的 `repository.html_url`,因此指向你的 Gitea 实例。
|
||||
|
||||
## 全局端点(`POST /webhook`)
|
||||
|
||||
全局端点使用运营者的全局密钥(`GITHUB_WEBHOOK_SECRET`、`GITEA_WEBHOOK_SECRET`)验签,并分发到**所有**路由。GitHub App 安装的事件都在此送达;在分组上设置 `installationId` 可保持租户隔离。
|
||||
|
||||
## 分组端点(`POST /webhook/{groupId}`)
|
||||
|
||||
每个分组都可以选择接入自己的 webhook 入口,使用独立的密钥(在分组页面的 _Webhook 端点_ 面板生成,owner 角色)。载荷使用**分组**的密钥验签,而不是全局密钥,并且只有该分组的路由会被触发。SaaS 用户以此配置 Gitea、经典 GitHub 或自定义 webhook,而无需共享(或知道)运营者的密钥。
|
||||
|
||||
- 支持任意提供方:GitHub(`X-Hub-Signature-256`)、Gitea(`X-Gitea-Signature`)、自定义(`X-WebHooker-Signature`)
|
||||
- 密钥为 64 位 hex 字符串;在控制台重新生成会立即失效旧密钥
|
||||
- 投递 id 去重键按租户隔离(`delivery:{groupId}:{id}`)
|
||||
- 分组没有密钥(或已不存在)时端点返回 `404`
|
||||
|
||||
## 自定义 Webhook
|
||||
|
||||
向 `POST /webhook/{groupId}`(或全局端点)POST 任意 JSON,并使用分组密钥将原始 body 的 HMAC-SHA256 以 `X-WebHooker-Signature: sha256=<hex>` 签名。载荷会变成 `custom` 事件,走正常的路由管线——创建一条 `event: custom` 的路由(控制台有模板),即可分发到该路由的目标、记录 `send_logs`,并出现在分组的 webhook 日志频道中。
|
||||
|
||||
载荷模式:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Deploy failed",
|
||||
"description": "Prod rollout failed at 12:03 UTC",
|
||||
"color": "red",
|
||||
"url": "https://ci.example.com/runs/42",
|
||||
"repo": "acme/widget",
|
||||
"author": {
|
||||
"name": "alice",
|
||||
"iconUrl": "https://…/alice.png",
|
||||
"url": "https://github.com/alice"
|
||||
},
|
||||
"fields": [{ "name": "Env", "value": "prod", "inline": true }],
|
||||
"footer": "my-monitor",
|
||||
"deliveryId": "alert-123"
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---------------|----------|----------------------------------------------------------------------------------------------------------|
|
||||
| `title` | string | 消息标题(缺省时为 "Custom message") |
|
||||
| `description` | string | 可选消息正文 |
|
||||
| `color` | string | 可选嵌入颜色:颜色词(`red`、`green`、`yellow`、`blue`、`purple`、`orange`、`cyan`、`gray`)或 `#rrggbb` |
|
||||
| `url` | string | 可选的标题链接 |
|
||||
| `repo` | string | 可选 `owner/repo`;作为标题前缀并用作页脚 |
|
||||
| `author` | object | 可选 `{ name, iconUrl, url }` |
|
||||
| `fields` | object[] | 可选嵌入字段 `{ name, value, inline }` |
|
||||
| `footer` | string | 可选页脚覆盖 |
|
||||
| `deliveryId` | string | 可选的发送方去重 id(重试) |
|
||||
|
||||
## GitHub App 租户隔离
|
||||
|
||||
GitHub App 安装后,**所有**安装方的事件都会到达全局端点。要让租户互相隔离,请把每个分组绑定到应当为其提供事件的安装 ID:`"installationId": 12345678`。该 ID 可从 App 安装 webhook 载荷(`installation.id`)或 GitHub App 安装页 URL 看到。即使分组的 `owners` 为空,来自其它安装的事件也会被拒绝。未设置 `installationId` 的分组保持旧行为(`owners` 过滤)。
|
||||
|
||||
绑定是**自动配置**的 —— 将 GitHub App 的 _Setup URL_ 指向 `{BASE_URL}/auth/github/install`。用户安装 App 后浏览器立即跳转到该页面(页面需要已登录的管理员会话——未登录用户会先被重定向走 OAuth 流程),可选择将安装绑定到:**新分组**(`inst-{installationId}`,默认)或任意**自己拥有 owner 权限的已有分组**(提交时再次校验角色;由 `POST /auth/github/install/bind` 完成配置)。无需手动填写 ID。作为兜底(例如未配置 Setup URL 时),`installation.created` webhook 事件也会自动创建/绑定分组 —— `owners` 匹配安装账号的现有分组会被绑定,否则创建独立的 `inst-{installationId}` 分组。之后在控制台为分组添加路由和成员即可。
|
||||
|
||||
要在选择页显示安装所属账号的登录名,请设置 `GITHUB_APP_ID` 与 `GITHUB_PRIVATE_KEY`——见[密钥](./configuration#密钥)。
|
||||
|
|
@ -34,4 +34,4 @@
|
|||
|
||||
## Webhook 日志频道
|
||||
|
||||
分组还可以在 Discord 频道/子区或 Telegram 群组/话题中接收每条 webhook 的摘要消息——见[分组 → Webhook 日志频道](./configuration#webhook-日志频道)。这些摘要是尽力发送的,**不会**记录到 `send_logs`。
|
||||
分组还可以在 Discord 频道/子区或 Telegram 群组/话题中接收每条 webhook 的摘要消息——见[分组 → Webhook 日志频道](./groups#webhook-日志频道)。这些摘要是尽力发送的,**不会**记录到 `send_logs`。
|
||||
|
|
|
|||
86
docs/zh/guide/routes.md
Normal file
86
docs/zh/guide/routes.md
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
# 路由与目标
|
||||
|
||||
路由决定哪些事件被转发到哪个频道(Discord 或 Telegram)。它们以 JSON 数组形式存储在 Cloudflare KV 的 `config:routes` 键下,可通过 [Web 控制台](./configuration#web-控制台)、[Admin API](../api/admin) 或 `config.example.yaml` 管理。
|
||||
|
||||
**没有默认路由**——每条路由都必须定义自己的目标。未配置任何路由时不会转发任何事件。每个实例最多可保存 **200 条路由**。
|
||||
|
||||
## 路由模式
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "unique-route-id",
|
||||
"name": "Human-readable name",
|
||||
"enabled": true,
|
||||
"groupId": "my-group",
|
||||
"fallback": false,
|
||||
"stop": false,
|
||||
"discordRoleIds": ["111111111111111111"],
|
||||
"filters": [
|
||||
{ "type": "event", "match": "push" },
|
||||
{ "type": "repo", "match": "org/repo", "exclude": false }
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"platform": "discord",
|
||||
"channelId": "REQUIRED_CHANNEL_ID",
|
||||
"threadId": "OPTIONAL_THREAD_ID"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
`targets` 的每一项都是一个推送目标,因此一条路由可同时转发到多个频道(例如一个 Discord 频道**和**一个 Telegram 群组)。`target.platform` 选择平台:`discord`(默认)或 `telegram`。**Discord** 目标要求 `target.channelId`(可选 `target.threadId` 指定子区);**Telegram** 目标要求 `target.chatId`(群组/超级群组 id,如 `-1001234567890`),可选 `target.topicId`(话题的 `message_thread_id`,相当于 Discord 子区)。没有默认频道回退。
|
||||
|
||||
| 字段 | 类型 | 必需 | 说明 |
|
||||
|------------------|----------|------|-----------------------------------------------------------------------------|
|
||||
| `groupId` | string | 是 | 路由所属[分组](./groups)的 id |
|
||||
| `fallback` | boolean | 否 | 为 `true` 时仅在没有其他非 fallback 路由匹配时才触发;其自身过滤器被忽略 |
|
||||
| `stop` | boolean | 否 | 为 `true` 且该路由匹配时,不再评估后续路由 |
|
||||
| `discordRoleIds` | string[] | 否 | 路由触发时要提醒的 Discord 身份组 id;仅对 Discord 目标生效 |
|
||||
|
||||
## Discord 身份组提醒
|
||||
|
||||
在路由上设置 `discordRoleIds` 可在其触发时提醒一个或多个 Discord 身份组(角色)。提醒(`<@&roleId>`)会加在路由所有 **Discord** 目标的消息内容前;Telegram 目标忽略该字段。只有当机器人拥有 `Mention Everyone` 权限(或身份组标记为可提及)且能看到该身份组时,提醒才会触发通知。
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "release-notify",
|
||||
"name": "Notify on Release",
|
||||
"enabled": true,
|
||||
"groupId": "default",
|
||||
"discordRoleIds": ["111111111111111111", "222222222222222222"],
|
||||
"filters": [{ "type": "event", "match": "release" }],
|
||||
"targets": [{ "platform": "discord", "channelId": "REQUIRED_CHANNEL_ID" }]
|
||||
}
|
||||
```
|
||||
|
||||
也可以在管理控制台的 _Discord 身份组提醒_ 中填写身份组 id。
|
||||
|
||||
## 过滤器
|
||||
|
||||
每条路由携带 `filters` 数组(全部匹配才触发——AND 逻辑)。见[过滤器类型](./configuration#过滤器类型)参考与[过滤器教程](./filters)。
|
||||
|
||||
## 自定义路由示例
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "backend-prs",
|
||||
"name": "Backend PRs",
|
||||
"enabled": true,
|
||||
"groupId": "backend-team",
|
||||
"filters": [
|
||||
{ "type": "repo", "match": "myorg/backend" },
|
||||
{ "type": "event", "match": "pull_request" },
|
||||
{ "type": "actor", "match": "[bot]", "exclude": true }
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"platform": "telegram",
|
||||
"chatId": "-1001234567890",
|
||||
"topicId": "9876543210"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
35
docs/zh/guide/storage.md
Normal file
35
docs/zh/guide/storage.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# 存储布局
|
||||
|
||||
## 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 有效期 |
|
||||
| `state:{hex}` | `{ redirectTo, expiresAt, discordUserId?, telegramUserId?, telegramChatId? }` | 600 秒 |
|
||||
| `invite:{token}` | `{ groupId, role, expiresAt, createdBy, note? }` | 7 天 |
|
||||
| `invite:group:{id}` | 每组的 Token 索引(保证邀请列表一致性) | 永久 |
|
||||
| `delivery:{id}` | Webhook 投递 id(去重标记) | 300 秒 |
|
||||
| `delivery:{groupId}:{id}` | 分组级 webhook 入口的租户级投递去重 | 300 秒 |
|
||||
| `tenant:{groupId}` | 分组 webhook secret(64 位 hex,控制台生成) | 永久 |
|
||||
| `msg:{routeId}:{key}:{target}` | 原地更新用消息 id 追踪(如 `workflow_run` / `check_run`) | 7 天 |
|
||||
| `cmd:guild:{id}` | 已注册命令的服务器 id(去重) | 永久 |
|
||||
| `cmd:registered:global` | 全局命令注册标记(去重) | 1 天 |
|
||||
| `config:discord-app-id` | 缓存的 Discord 应用 id | 永久 |
|
||||
| `i18n:{lang}` | 叠加在英文之上的翻译覆盖 | 永久 |
|
||||
|
||||
## D1 存储布局
|
||||
|
||||
D1 数据库(`DB` 绑定,数据库 `webhooker`)包含四张表:
|
||||
|
||||
| 表 | 用途 |
|
||||
|-------------------|--------------------------------------------------------------------------------------------------|
|
||||
| `send_logs` | 每次分发尝试一行(路由 id、事件、目标、ok/error、耗时、错误码、详情) |
|
||||
| `audit_logs` | 每次管理员操作一行(登录/登出、分组/路由/成员/邀请变更) |
|
||||
| `discord_links` | 映射 `discord_user_id` → `github_user_id`,供 `/gh` Discord 命令使用 |
|
||||
| `telegram_links` | 映射 `telegram_user_id` → `github_user_id`,供 `/gh` Telegram 命令使用 |
|
||||
|
||||
`audit_logs` 由定时任务在 `AUDIT_RETENTION_DAYS`(默认 90)后自动清理。行字段说明见[日志](./logs)。
|
||||
Loading…
Add table
Add a link
Reference in a new issue