切换主题
Webhook 自动触发
Webhook 让 Git 平台的推送自动触发构建部署任务,无需人工点「运行任务」。管理端为每个启用 Webhook 的项目提供一个匿名可访问的投递端点,平台推送后经「定位项目 → 验签 → 过滤 → 防抖 → 建任务/入队」处理,并立即返回结果(不等待任务执行完)。
- 触发后的执行、日志、通知与人工触发完全同一条链路,执行端仍只认
run_task指令。 - 端点与密钥在项目配置页的「Webhook」Tab 维护,见 项目管理。
- 任务触发、队列与状态流转见 任务与队列;任务通知见 通知。
端点与地址
投递端点为:
POST /api/hooks/git/{hookKey}1
- 匿名可访问:不校验 JWT,也不要求任何登录态;安全依赖随机
hookKey、平台验签、体积上限与速率限制。 - 请求体必须是该平台的 Webhook 报文(JSON),例如 GitHub 的 push 报文、GitLab 的 Push Hook 报文。
- 成功建任务返回
202,被忽略/合并返回200,被拒绝返回4xx。
端点地址的拼接与 baseUrl
页面上展示、复制给 Git 平台的那个地址由 server.baseUrl 拼出:
{server.baseUrl}/api/hooks/git/{hookKey}1
server.baseUrl 未配置时,管理端会按监听地址推断(0.0.0.0 视为 127.0.0.1),得到的是只能本机访问的内网地址,Git 平台投递不到。因此需要外部访问必须显式配置 server.baseUrl(如 https://cicd.example.com,末尾不带 /),改完重启管理端生效。
接口返回的 baseUrlConfigured 标识地址来源:true 表示取自配置文件的 server.baseUrl,false 表示当前是推断出的内网地址。前端据此给出提示,配置页上的端点地址是只读的,可一键复制。
hookKey 的生成与重置
- 项目首次保存并启用 Webhook 时,管理端生成
hookKey(crypto/rand24 字节随机数 → hex 编码,共 48 个字符),存入project.config.webhook.key。 - 端点路径用随机值而非项目 ID,避免被枚举刷任务。
- 配置页提供「重置地址」:重置后
hookKey立即变更、旧地址立即失效,需要到 Git 平台重新填写。重置操作会写审计日志。
体积上限与限流
| 配置项 | 默认值 | 说明 |
|---|---|---|
webhook.maxBodyKB | 1024(1MB) | 单次投递请求体上限,超过返回 413 并记一条 rejected 投递。读取时多读 1 字节用于判断超限,超限由服务层拒绝并留痕 |
webhook.limitPerMinute | 120 | 按项目统计的投递频率上限(次/分钟),超出返回 429 并记 rejected |
webhook.debounceSeconds | 5 | 防抖窗口的全局默认值,项目未配置 debounceSeconds 时生效 |
webhook.deliveryRetentionDays | 30 | 投递记录保留天数,由派发器定时清理 |
判定与建任务都在项目级互斥锁内完成(锁最多等待 5 秒),避免并发投递或多实例同时收到同一次推送时,限流被突破、防抖合并失效或重复建任务;等待超时返回
429(原因「投递过于密集,请稍后重试」)。
平台与验签
provider 决定验签方式与报文字段解析。当前支持 5 个平台,验签在 JSON 解析之前用原始 body 完成(否则校验会失效)。密钥在库中为 AES-256-GCM 密文,接口不回显。
provider | 验签请求头 | 校验方式 |
|---|---|---|
github | X-Hub-Signature-256 | 去掉 sha256= 前缀后,与 HMAC-SHA256(原始 body, secret) 的 hex 值做恒时比较(大小写不敏感) |
gitlab | X-Gitlab-Token | 与 secret 明文做恒时比较 |
gitee | X-Gitee-Token | 与 secret 明文做恒时比较 |
codeup | X-Codeup-Token | 与 secret 明文做恒时比较(阿里云云效 Codeup 的 Secret Token) |
generic | 可配置(默认 X-CICD-Token,或查询参数 ?secret=) | 取值位置、名称与校验方式均可配置(见下),默认优先取请求头、缺失时取查询参数,再与 secret 做恒时比较 |
仅
provider=generic支持自定义验签取值方式;其它平台仍按各自固定规则验签。通用平台可配置:
secretHeader/secretQuery:取值请求头名 / 查询参数名,留空分别回退X-CICD-Token/secret;取值时先请求头、后查询参数。verifyMode:token(默认,取到的值与 secret 恒时比较)/hmac(用 secret 对原始 body 做 HMAC-SHA256 后比较)。signaturePrefix:HMAC 模式下可选的前缀(如sha256=),比较前先去除。signatureEncoding:HMAC 签名的编码,hex(默认,大小写不敏感)/base64(区分大小写)。
各平台解析事件所用的请求头:
provider | 事件请求头 | 说明 |
|---|---|---|
github | X-GitHub-Event | push / create / pull_request |
gitlab | X-Gitlab-Event | Push Hook / Tag Push Hook / Merge Request Hook |
gitee | X-Gitee-Event | 同上(报文结构与 GitLab 基本一致) |
codeup | Codeup-Event | 同上 |
generic | 无(读报文体内 event 字段) | 报文自带 event / ref / refType / commit / message / author / paths |
解析后的事件类型统一归一化为 push / tag / merge_request,供过滤规则使用。
密钥留空 = 不验签
project.config.webhook.secret 留空时跳过验签(不调用验签逻辑),端点退化为「只靠随机 hookKey 保密」——任何拿到地址的人都能触发构建部署。
- 此模式仅建议内网或测试环境使用;生产环境必须配置密钥。
- 前端在「已启用但未配置密钥」时显示红色告警:「未配置验签密钥:任何拿到端点地址的人都能触发构建部署,仅建议内网或测试环境使用」。
- 密钥与端点地址同页维护:可「随机生成」一串随机密钥(32 字节随机数转 base64url),复制后粘贴到 Git 平台的 Webhook 密钥处,再保存本页;留空保存表示不修改已设置的密钥。
过滤规则
配置在 project.config.webhook,逐项如下(默认值与实现一致):
| 字段 | 说明 | 默认值 |
|---|---|---|
enabled | 是否启用;未启用时端点直接拒绝投递 | 关闭 |
provider | 平台:github / gitlab / gitee / codeup / generic,决定验签方式与事件字段解析 | generic |
secret | 验签密钥(密文存储,不回显);留空表示不验签 | 空 |
secretHeader | 通用平台取密钥的请求头名(仅 provider=generic 生效) | X-CICD-Token |
secretQuery | 通用平台取密钥的查询参数名(仅 provider=generic 生效) | secret |
verifyMode | 通用平台校验方式:token(明文令牌)/ hmac(HMAC-SHA256) | token |
signaturePrefix | HMAC 签名前缀(如 sha256=),比较前去除 | 空 |
signatureEncoding | HMAC 签名编码:hex / base64 | hex |
events | 允许的事件数组:push / tag / merge_request | ["push"](空数组同样按 push 处理) |
branchFilter | 分支过滤,glob 数组(如 main、release/*);空数组表示不限制 | 空(不限制) |
tagFilter | tag 过滤,glob 数组(如 v*);tag 事件用它匹配 | 空(不限制) |
pathFilter | 变更文件路径过滤,glob 数组(如 src/**);空数组表示不限制 | 空(不限制) |
refSource | 用分支来源:project(用项目配置的分支)/ webhook(用推送的分支或 tag) | webhook |
actions | 触发范围 {build,deploy,start,fromStage} | 未配置时按全流程执行 |
queuePolicy | 资源被占用时:always(排队)/ skip(本次忽略,记 ignored) | always |
debounceSeconds | 防抖窗口(秒):窗口内同项目多次推送只建一个任务,取最后一次的 commit | 5(未配置时回退全局默认 5) |
skipCiKeyword | 提交信息包含该关键字时跳过本次构建 | [skip ci](留空也按默认值判断) |
queuePolicy的实际取值是always与skip(不是queue):always表示资源被占用时照常入队排队,skip表示同项目已有未结束任务时丢弃本次投递。
glob 匹配语义
*:匹配不跨/的任意字符([^/]*)。**:匹配跨任意层级(.*);**/特化为(?:.*/)?,可匹配零层或多层目录(如src/**、**/*.go)。?:匹配单个非/字符。- 过滤时同时用原始 ref(如
refs/heads/main)与归一化后的短名(main)匹配,两种写法都兼容。
短路顺序
过滤按顺序短路,任一步不通过即停止,并把原因写入 webhook_delivery.reason:
| 顺序 | 判定 | 命中时的处理 |
|---|---|---|
| 1 | 事件:是否在 events 内 | ignored,理由如「事件不匹配:本次为 tag,允许 push」 |
| 2 | 分支 / tag:tagFilter(tag 事件)或 branchFilter(分支与合并请求) | ignored,理由如「分支不匹配过滤规则:dev」 |
| 3 | 路径:pathFilter(未配置或平台未提供变更列表时不限制) | ignored,理由「变更文件不在过滤范围内:共 N 个文件」 |
| 4 | 提交信息:命中 skipCiKeyword | ignored,理由「提交信息包含 [skip ci],跳过本次构建」 |
| 5 | 防抖:窗口内已有同项目成功投递 | merged,不新建任务 |
| 6 | 队列策略:queuePolicy=skip 且同项目已有未结束任务 | ignored |
只有全部通过才建任务:trigger_type=webhook、triggered_by=推送人,分支/commit 写入任务与投递记录。当 refSource=webhook 时,用推送的分支/tag 覆盖 git.ref(推哪个分支就构建哪个分支)。
处理流程
响应结构
成功建任务立即返回 202(不等待任务执行完):
json
{
"deliveryId": 1024,
"taskId": 358,
"status": "accepted",
"reason": "已建任务",
"message": "已入队,当前位次 2",
"queued": true,
"queuePosition": 2
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
- 资源就绪被直接派发时,
queued=false、不带queuePosition,message为「已派发执行」。 - 排队时
queued=true并给出queuePosition(当前位次);排队原因与位次含义见 任务与队列。 - 被忽略或被防抖合并时返回
200,用status区分(ignored/merged),并附reason:
json
{
"deliveryId": 1025,
"status": "ignored",
"reason": "分支不匹配过滤规则:dev",
"message": "分支不匹配过滤规则:dev",
"queued": false
}1
2
3
4
5
6
7
2
3
4
5
6
7
设计稿用
{ignored:true,reason}简写表示「未触发建任务」,实际响应体以status字段区分(ignored/merged),并同样带reason。
被拒绝(rejected)时返回对应 4xx 状态码与原因,例如「验签失败:…」「项目未启用 Webhook」「端点不存在或已失效」。
投递留痕与排查
无论接受、忽略、合并还是拒绝,都会写一条 webhook_delivery 记录,用于回答「为什么没有触发」。项目详情「Webhook」Tab 展示最近投递(状态色标 + 原因文案),站内「Webhook 投递」页可按项目/分组/状态/时间范围查询全部投递。
记录字段
| 字段 | 含义 |
|---|---|
id | 投递 ID(deliveryId) |
project_id / project_name | 归属项目;端点不存在时无法归属,project_id 记为 0 仍留痕,便于排查端点被刷 |
provider | 平台 |
event | 归一化事件类型(push / tag / merge_request) |
ref / ref_type | 归一化后的分支 / tag 名,及其类型(branch / tag) |
commit / commit_message | 提交 SHA 与提交信息(首行,最长 200 字符) |
author | 推送人 |
status | 投递状态,见下表 |
reason | 结论原因(过滤不通过、验签失败、限流等) |
task_id | 建任务成功时的任务 ID,否则为 0 |
remote_ip | 来源 IP(重放时为 replay) |
body | 原始报文,截断存储,最多 8KB,不存 secret |
created_at | 投递时间 |
状态取值
status | 含义 | 典型 HTTP |
|---|---|---|
accepted | 已建任务(并交队列/派发) | 202 |
merged | 防抖窗口内合并到已有任务,不新建 | 200 |
ignored | 规则不匹配(事件、分支/tag、路径、提交信息、队列策略 skip) | 200 |
rejected | 验签失败 / 端点不存在 / 未启用 / 限流 / 体积超限 | 4xx |
failed | 内部异常(如解密密钥失败、建任务失败) | 4xx / 500 |
如何定位「为什么没触发」
- 在「最近投递」中找到对应时间的记录(可按项目过滤),先看
status:- 没有记录:说明请求根本没到管理端——检查
server.baseUrl是否为外部可达地址、Git 平台配置的地址是否正确、网络与反向代理是否放行。 rejected:看reason——「验签失败」说明平台密钥与管理端不一致;「端点不存在或已失效」多为重置地址后未更新平台配置;「超过速率限制」说明推送过于频繁。ignored:看reason——按提示调整events/branchFilter/tagFilter/pathFilter/skipCiKeyword/queuePolicy。merged:属于正常合并,说明防抖窗口内有更早的推送已建任务,本次取最后一次的 commit 合并处理。accepted:已触发,可点任务 ID 跳转任务详情。
- 没有记录:说明请求根本没到管理端——检查
- 调试规则时可用两种手段(仅管理员):项目配置页的「发送测试投递」(默认
dryRun,只返回判定结果、不建任务、不留痕)与投递列表的「重放」(POST /api/webhooks/deliveries/:id/replay,用历史投递原始报文重新触发,忽略验签、防抖与事件限制)。「测试并真实触发」会真实建任务。
各平台配置示例
通用步骤:在项目配置页「Webhook」Tab 开启「启用」→ 选平台 → 复制「端点地址」→ 填「验签密钥」并与平台侧保持一致 → 勾选触发事件 → 保存。以下地址中的 https://cicd.example.com 需替换为你实际配置的 server.baseUrl。
GitHub
- Payload URL:
https://cicd.example.com/api/hooks/git/{hookKey} - Content type:
application/json - Secret:填入与管理端一致的验签密钥(对应
X-Hub-Signature-256) - 事件:勾选
Push(推送 tag 也会以 push 报文到达并归一化为tag);如需合并请求触发,再勾选Pull requests - 管理端平台选「GitHub」
GitLab
- URL:
https://cicd.example.com/api/hooks/git/{hookKey} - Secret token:填入与管理端一致的密钥(对应
X-Gitlab-Token) - 触发事件:勾选
Push events、Tag push events、Merge request events中需要的项 - 管理端平台选「GitLab」
Gitee
- URL:
https://cicd.example.com/api/hooks/git/{hookKey} - 密码(Webhook 密码):填入与管理端一致的密钥(对应
X-Gitee-Token) - 事件:勾选
Push、Tag Push、Merge Request中需要的项 - 管理端平台选「Gitee」
阿里云云效 Codeup
- Webhook 地址:
https://cicd.example.com/api/hooks/git/{hookKey} - Secret Token:填入与管理端一致的密钥,平台会通过
X-Codeup-Token请求头发送 - 事件:勾选 push / tag / 合并请求中需要的项(事件名走
Codeup-Event头) - 管理端平台选「Codeup」即可
通用(generic)
自建或非内置平台可用「通用」:把报文构造成 {event, ref, refType, commit, message, author, paths},密钥可放在 X-CICD-Token 请求头,或放在地址的 ?secret= 查询参数中。
相关接口
| 方法 | 路径 | 权限 | 说明 |
|---|---|---|---|
| POST | /api/hooks/git/{hookKey} | 匿名 | Git 平台投递入口 |
| GET | /api/projects/:id/webhook | view | 查看配置与端点地址(secret 不回显,仅返回是否已设置;baseUrlConfigured 标识地址来源) |
| PUT | /api/projects/:id/webhook | manage | 保存配置(enabled/provider/secret/events/branchFilter/tagFilter/pathFilter/refSource/actions/queuePolicy/debounceSeconds/skipCiKeyword) |
| POST | /api/projects/:id/webhook/reset-key | manage | 重置端点标识(旧地址立即失效) |
| POST | /api/projects/:id/webhook/test | manage | 发送样例投递(默认 dryRun,只返回判定结果不建任务) |
| GET | /api/webhooks/deliveries | 登录 | 投递记录分页(projectId/groupId/status/from/to) |
| POST | /api/webhooks/deliveries/:id/replay | admin | 按历史投递重放(忽略验签、防抖与事件限制) |
Webhook 配置变更、地址重置与投递重放都会写审计日志,可在「系统管理 → 操作审计」中查询与追溯。