fix(deploy): 部署源改用已提交 origin/main 树(独立检出),根治「开发区任何 modified 即中止」
ci/woodpecker/push/main Pipeline was successful

单 project-20260921-deploy-dirtyguard-rootfix(任总 2026-09-21 10:28「根治」)。

问题:开发区 /root/cma-management → /srv/hermes/shared/cma-management 既是编辑区又是部署源,
deploy.sh [0] 对任何 tracked modified 即 exit 1,多 agent 并行下反复自锁:
- 2026-09-18 frontend/package.json(corepack 生成物)
- 2026-09-21 10:09 batch5 在途 6 文件(放行卡住)
- 2026-09-21 11:07 构建又写出 frontend/components.d.ts

改动:
- deploy.sh:部署内容 = 已提交的 origin/main(独立部署检出 /srv/hermes/shared/cma-deploy:
  fetch -> checkout --detach -f -> clean -fdx);[0] 降级为告警(不再 exit);
  新增 1.1 部署树自检(部署树必须无 tracked 修改)、1.2 运行时资产单源接线(.env/venv/node_modules)、
  1d 后端可导入自检、运行树幂等切换(unit 改写前备份 + 一行回滚,cma-runtime-unit-switch 可抽取块);
  保留 [1b] 鉴权面审计闸门(B 类缺口即中止)与 构建->铺站->重启->冒烟 全流程;
  新增 drill 模式(离线演练:www 必须在 /var/www 之外、systemctl/nginx 必须是 PATH 桩、迁移只 --check)。
- deploy/cma-deploy-dirty-guard.sh:宿主前置闸门降级为告警(仅仓库不可用时失败关闭),不再写开发区。
- deploy/gitea-cma-deploy-hook.sh:[0] 段文案/语义同步(gate-trail 留痕链原样保留)。
- deploy/install-host-deploy-hook.sh:宿主组件安装/升级(备份 + md5 校验 + --check)。

演练证据(26/26 PASS):脏区旧版 [0] exit=1 / 新版整链 exit=0;开发区在途改动逐字节保留;
构造 B 类缺口时 [1b] 中止且未铺站;真机 drill 零生产影响。

未 push(发布须任总放行)。
This commit is contained in:
wecom-fullstack
2026-09-21 11:13:30 +08:00
parent 42ff836309
commit adfc3ac845
4 changed files with 438 additions and 30 deletions
+65
View File
@@ -0,0 +1,65 @@
#!/bin/bash
# ============================================================
# 宿主部署链组件安装/升级(CMA)
# cma-deploy-source-decouple-20260921(单 project-20260921-deploy-dirtyguard-rootfix)
#
# 把本仓 deploy/ 下的宿主侧组件安装到 /usr/local/sbin/(改前自动备份、改后校验 md5)。
# 组件(宿主侧,容器内 gitea post-receive → SSH forced-command 进入本仓库时执行):
# gitea-cma-deploy-hook.sh → /usr/local/sbin/gitea-cma-deploy-hook.sh
# cma-deploy-dirty-guard.sh → /usr/local/sbin/cma-deploy-dirty-guard.sh
#
# 用法:
# bash deploy/install-host-deploy-hook.sh # 安装/升级(含备份 + 校验)
# bash deploy/install-host-deploy-hook.sh --check # 只比对(不写任何文件)
#
# 说明:
# - 备份目录 /root/backups/cma-deploy-source-decouple-<YYYYMMDD-HHMMSS>/
# - 一行回滚: cp <备份目录>/<文件名> /usr/local/sbin/<文件名> && md5sum -c <备份目录>/MD5SUMS.rollback
# ============================================================
set -euo pipefail
REPO_DIR="$(cd "$(dirname "$0")/.." && pwd)"
SRC_DIR="$REPO_DIR/deploy"
DST_DIR="/usr/local/sbin"
FILES=(gitea-cma-deploy-hook.sh cma-deploy-dirty-guard.sh)
MODE="${1:-install}"
for f in "${FILES[@]}"; do
[ -r "$SRC_DIR/$f" ] || { echo "❌ 源文件缺失: $SRC_DIR/$f"; exit 1; }
done
if [ "$MODE" = "--check" ]; then
rc=0
for f in "${FILES[@]}"; do
if [ -r "$DST_DIR/$f" ] && cmp -s "$SRC_DIR/$f" "$DST_DIR/$f"; then
echo "✓ 一致: $DST_DIR/$f"
else
echo "≠ 不一致: $DST_DIR/$f(需要安装)"; rc=1
fi
done
exit "$rc"
fi
TS="$(date +%Y%m%d-%H%M%S)"
BAK_DIR="/root/backups/cma-deploy-source-decouple-$TS"
mkdir -p "$BAK_DIR"
for f in "${FILES[@]}"; do
if [ -e "$DST_DIR/$f" ]; then
cp -a "$DST_DIR/$f" "$BAK_DIR/$f"
md5sum "$DST_DIR/$f" >> "$BAK_DIR/MD5SUMS.rollback"
else
echo "<absent>" >> "$BAK_DIR/MD5SUMS.rollback"
fi
done
for f in "${FILES[@]}"; do
install -m 0755 -o root -g root "$SRC_DIR/$f" "$DST_DIR/$f"
done
echo "备份目录: $BAK_DIR"
for f in "${FILES[@]}"; do
echo "已安装: $DST_DIR/$f md5=$(md5sum "$DST_DIR/$f" | awk '{print $1}')"
done
bash -n "$DST_DIR/gitea-cma-deploy-hook.sh" && echo "✓ 语法检查通过"
echo "✓ 安装完成(生效于下一次 push 触发的部署)"