feat(deploy): trigger JD agent after human merge

This commit is contained in:
冰朔 2026-08-06 13:35:10 +08:00
commit 564859b1ce
9 changed files with 517 additions and 8 deletions

View file

@ -1,19 +1,21 @@
# HLCC-PUSH-TO-DEPLOY-EVENT-PROTOCOL
状态:本地实现候选,尚未部署;当前现实层不得宣称可派发
状态:人工合并自动部署桥实现候选服务器常驻部署Agent已在线合并门待本提交部署与实测
语言层在冰朔明确确认“该提交需要部署”后,主动发出 `guanghu.deployment-intent/v1`。推送本身不会产生部署事件。意图必须绑定:
普通推送本身不会产生部署事件。AI把代码和部署清单推入开发分支后只有冰朔在光湖代码频道人工合并到 `main`,合并门才把该次合并实际改动的部署清单转换为 `guanghu.deployment-event/v1`。事件必须绑定:
- 代码频道仓库、分支和完整提交 SHA
- `REQUEST-ID@完整提交SHA` 的不可变资源;
- `deployment/requests/` 下的部署清单。
语言人格体通过 `/api/deployment/dispatch` 派发这一意图;接口要求一张单独的 `server-ops / dispatch-approved-deployment` 工单,且资源必须为同一 `REQUEST-ID@完整提交SHA`。服务端才写入 `guanghu.deployment-event/v1` 到本机队列。常驻部署 Agent 订阅此队列,读取同一提交中的清单,执行备份、部署、健康检查与回滚,并将回执回写到原工单
Forgejo以HMAC-SHA256向 `/authz/api/deployment/forgejo-merge` 发送 `pull_request` 事件。合并门只接受 `action=closed`、`merged=true`、`merged_by=bingshuo`、目标仓库为 `bingshuo/guanghu-ice-heart` 且目标分支为 `main` 的事件随后通过Forgejo只读API取得该PR改动文件。只有 `deployment/requests/<REQUEST-ID>.json` 被新增或修改时才写入队列。常驻部署 Agent 读取同一提交中的清单,执行备份、部署、健康检查与回滚。
没有部署意图的提交照常入库,回执为 `not_requested`;无效意图回执为 `rejected`,不会部署。推送工单绝不扩大为部署权限;服务器也不扫描仓库主动拉取部署。
人工合并本身就是本次部署批准,不再重复创建 `dispatch-approved-deployment` 工单。原 `/api/deployment/dispatch` 保留为没有代码频道合并界面时的兼容/灾备入口,不再作为正常发布流程。
没有部署清单的合并照常入库但不部署普通push、关闭未合并、非登记合并者、错误签名、仓库/分支不匹配和无效事件均不会部署。服务器不扫描仓库猜测部署同一Forgejo delivery与清单通过持久去重标记最多入队一次。
`resource` 中的 `REQUEST-ID` 必须与清单文件名完全一致:`deployment/requests/<REQUEST-ID>.json`。批准 A 而执行 B 必须在派发端和常驻 Agent 端分别拒绝。
首次新单元使用 `guanghu.architecture-provision-request/v1`;已经在线的 systemd 服务必须使用 `guanghu.existing-service-update-request/v1`,先完整备份声明目标,再重启和逐项验收,失败恢复全部旧文件与旧单元。二者不得互相冒充。
当前京东节点若尚未安装 `/api/deployment/dispatch`、事件队列和常驻 worker则先通过已有的主人邮件批准固定管理动作引导这套运行时。没有这个固定引导动作时应回执 `BOOTSTRAP_ACTION_NOT_DEPLOYED`,不得绕回人类 SSH 或云控制台,也不得发送一张服务器根本不会执行的部署工单
首次安装合并门时由冰朔已授权且持有本机专用密钥的当前实例按不可变候选提交、完整备份、健康检查和服务器私有回执完成一次性引导不得为此绕回工单。引导完成后正常发布只走“AI开发分支 → 合并请求 → 冰朔人工合并 → 自动部署与回执”

View file

@ -0,0 +1,92 @@
{
"schema": "guanghu.existing-service-update-request/v1",
"request_id": "HLCC-HUMAN-MERGE-AUTO-DEPLOY-20260806",
"target_node": "JD-FD-PRIMARY",
"status": "SERVICE_UPDATE_PACKAGE_READY · DEPLOYMENT_PENDING",
"purpose": {
"what": "把光湖代码频道中由冰朔人工完成的main合并转换为不可变部署事件交给京东常驻部署Agent执行。",
"why": "服务器已经具备清单校验、备份、部署、健康检查、回滚和回执能力,但代码频道的合并事件尚未接到部署队列,导致每次合并后仍需再次派发。",
"success": "仅Forgejo已合并PR且merged_by=bingshuo、目标仓库和分支匹配、改动包含deployment/requests下的有效清单时入队普通push、关闭未合并、错误签名、其他合并者和重复投递均不产生第二次部署。",
"out_of_scope": [
"不因普通Git push自动部署",
"不执行PR或仓库提供的命令",
"不允许清单选择目标服务器或扩大权限",
"不修改光湖OS磁盘、内核、引导或启动状态"
]
},
"module": {
"unit": "lake-lamp-authz.service",
"run_user": "guanghu-authz",
"install_root": "/opt/guanghu/lake-lamp-authz"
},
"service_update": {
"kind": "existing-systemd-service",
"require_existing_unit": true,
"required_existing_files": [
"server.js",
"deployment-event.js"
]
},
"unit_source": "server-tools/lake-lamp-authz/lake-lamp-authz.service",
"files": [
{
"source": "server-tools/lake-lamp-authz/server.js",
"destination": "server.js",
"mode": "0644"
},
{
"source": "server-tools/lake-lamp-authz/deployment-event.js",
"destination": "deployment-event.js",
"mode": "0644"
},
{
"source": "server-tools/lake-lamp-authz/forgejo-merge-deployment.js",
"destination": "forgejo-merge-deployment.js",
"mode": "0644"
}
],
"runtime_check": {
"url": "http://127.0.0.1:3921/health",
"expected": {
"ok": true,
"service": "lake-lamp-authz",
"merge_deployment_gate": {
"configured": true,
"mode": "human-merged-pull-request-only"
}
}
},
"acceptance_checks": [
{
"url": "http://127.0.0.1:3921/api/public/capabilities",
"expected": {
"schema": "guanghu.lake-lamp-public-workorder/v1"
}
}
],
"bootstrap": {
"one_time": true,
"reason": "本清单合并前合并门尚不存在;首次由当前已授权实例按完整候选提交和同一回滚执行器安装,之后由人工合并自动触发。",
"webhook_target": "https://guanghulab.com/authz/api/deployment/forgejo-merge",
"webhook_event": "pull_request",
"secret_location": "/etc/guanghu/secrets/lake-lamp/authorization.env",
"secret_committed": false
},
"rollback": {
"automatic_on_failure": true,
"scope": "恢复server.js、deployment-event.js、原systemd单元并移除新增门模块然后重启旧服务",
"receipt_required": true
},
"security": {
"hmac_sha256_required": true,
"allowed_repository": "bingshuo/guanghu-ice-heart",
"allowed_branch": "main",
"allowed_mergers": [
"bingshuo"
],
"max_deployment_manifests_per_merge": 5,
"delivery_idempotency": true,
"repository_commands_executed": false,
"no_secrets": true
}
}