feat(deploy): 发布链地基三件套——webhook 骨架/构建占位/回滚干跑

- webhook-receive.sh:HMAC 骨架 + 仅 main 分支触发(干跑验证两条 ref 路径)
- build.sh:锁发布链形态与路径约定,astro 命令留 Phase 1 TODO
- rollback-dryrun.sh:回滚四前置条件验证 + 人为操作手册(秒级回 18090)
- staging 落用户区 ~/docker_apps/blog/www-staging(宿主 sudo 不可用,nginx 以 root 读用户目录无碍)

验证: webhook 干跑 main accepted / non-main ignored;rollback-dryrun
      四要素 ok(halo vhost/容器/响应/staging)

Co-authored-by: GLM-5.3
This commit is contained in:
wait4xandGLM-5.3 committed 2026-10-24 22:10:59 +08:00
1 parent ddcda54f90
commit f16b9487d3
4 files changed
+87 -2

No files matched your search

+37
View File
@@ -0,0 +1,37 @@
#!/bin/sh
# gitea webhook 接收骨架(Phase 0:仅鉴权与触发框架,构建动作为占位)
#
# 为什么 shell 而非服务:单用户发布链,gitea webhook 直接 POST 到本机端口
# 需要常驻服务;Phase 0 先以 gitea 侧 webhook → 本脚本(经 systemd path 或
# 手动)的形态落骨架,Phase 4 再决定是否升级为常驻接收器。
#
# 用法(Phase 0 干跑): sh infra/deploy/webhook-receive.sh --dry-run <payload.json>
# 真实接入(Phase 4): gitea 仓 webhooks → URL 指向接收器,X-Gitea-Signature 头做 HMAC-SHA256
set -e
DRY_RUN=0
[ "${1:-}" = "--dry-run" ] && DRY_RUN=1 && shift
# SECRET 从宿主私有文件读取,绝不入库(与 gitea init-credentials.txt 同策略)
SECRET_FILE="$HOME/docker_apps/gitea/webhook-secret.txt"
PAYLOAD="${1:?usage: webhook-receive.sh [--dry-run] <payload.json>}"
verify_signature() {
# Phase 4 实装:openssl sha256 与 X-Gitea-Signature 比对;干跑跳过
# 密钥文件路径固定如上,存在性检查失败时只报固定文案,不回显路径变量
test "$DRY_RUN" = "1" && { echo "[dry-run] signature check skipped"; return 0; }
test -s "$SECRET_FILE" || { echo "missing webhook secret file" >&2; exit 1; }
echo "TODO(phase4): HMAC-SHA256 verify" >&2; exit 9
}
trigger_build() {
# 仅接受 push 到默认分支的事件(payload 的 ref 字段),防误触发
if python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); sys.exit(0 if d.get("ref","").endswith("/main") else 1)' "$PAYLOAD"; then
echo "[webhook] push to main accepted -> build.sh"
if [ "$DRY_RUN" = "1" ]; then echo "[dry-run] build skipped"; else sh "$(dirname "$0")/build.sh"; fi
else
echo "[webhook] non-main ref ignored"
fi
}
verify_signature
trigger_build