#!/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 # 真实接入(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] }" 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