fix(deploy): AC11 reject unknown args + add --help/--dry-run (no side effects on error paths)

This commit is contained in:
小唯
2026-10-19 03:11:53 +08:00
parent 8f38c2de0c
commit ae766a88bb
+58 -6
View File
@@ -16,7 +16,28 @@ set -euo pipefail
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
BIN_DIR="${BIN_DIR:-/home/muc/bin}"
# --allow-dirty:显式承担「把在途改动编进生产二进制」的风险(默认拒绝)
# 用法/帮助(t_debe2002 AC11):--help 打印用法后 exit 0,不构建不停止服务;
# 未知参数(--help2/--foo/空串)打印用法 + exit 2,绝不进入部署流程。
# 背景:AC11 由验收在评审时亲自踩到 —— 原先未知参数被静默忽略后走完整部署
# (一个手滑的 --help 就触发一次「构建+停服务+重启+7分钟CPU尖峰」)。
# 本脚本的主题正是「错误路径上不应有副作用」,未知参数是被忽略后触发完整部署
# = 同类缺陷的入口版,故必须拒绝。
usage() {
cat <<'EOF'
用法:
./scripts/deploy.sh 完整部署: 构建两+装两+停两+启两+校验
./scripts/deploy.sh --help 打印本用法后退出(不构建/不停止/不启动)
./scripts/deploy.sh --dry-run 跑前置闸门 + 打印将执行的动作后退出(不写/不停/不启)
./scripts/deploy.sh --verify 只校验「运行二进制 sha ∈ 部署清单」的自证版本(独立动作,不构建)
./scripts/deploy.sh --verify-only 只跑全量校验(不构建/不安装/不重启)—— 反例测试/人工体检用
./scripts/deploy.sh --mark-approved 评审通过后把当前 HEAD 追加进已批准部署清单(独立动作)
./scripts/deploy.sh --allow-unreviewed 显式承担「构建范围含未评审提交」的风险(默认拒绝)
./scripts/deploy.sh --allow-dirty 显式承担「把在途改动编进生产二进制」的风险(默认拒绝)
make deploy = ./scripts/deploy.sh
未知参数 → 打印本用法 + exit 2(t_debe2002 AC11:手滑的参数不得触发一次无人要的部署重启)。
EOF
}
ALLOW_DIRTY=0
# --allow-unreviewed:显式承担「把未经评审的提交编进生产」的风险(默认拒绝)
ALLOW_UNREVIEWED=0
@@ -24,11 +45,23 @@ ALLOW_UNREVIEWED=0
MARK_APPROVED=0
# --verify:只校验「运行二进制 sha ∈ 部署清单」的自证版本(AC8 选项3,独立动作,不构建/不安装/不重启)
VERIFY_MANIFEST=0
# --verify-only:只跑全量校验(AC1-AC10 时代即有的独立动作,不构建/不安装/不重启)
VERIFY_ONLY=0
# --dry-run:跑前置闸门 + 打印将执行的动作,不写/不停/不启(AC11)
DRY_RUN=0
for _a in "$@"; do
[ "$_a" = "--allow-dirty" ] && ALLOW_DIRTY=1
[ "$_a" = "--allow-unreviewed" ] && ALLOW_UNREVIEWED=1
[ "$_a" = "--mark-approved" ] && MARK_APPROVED=1
[ "$_a" = "--verify" ] && VERIFY_MANIFEST=1
case "$_a" in
--help) usage; exit 0 ;;
--dry-run) DRY_RUN=1 ;;
--allow-dirty) ALLOW_DIRTY=1 ;;
--allow-unreviewed) ALLOW_UNREVIEWED=1 ;;
--mark-approved) MARK_APPROVED=1 ;;
--verify) VERIFY_MANIFEST=1 ;;
--verify-only) VERIFY_ONLY=1 ;;
# t_debe2002 AC11:未知参数(含 --help2/--foo/空串)→ 打印用法 + exit 2,绝不进入部署流程。
# 用独立的 unknown() 而非 die(),因为 die 固定 exit 1,而 AC11 要求未知参数 exit 2。
*) printf '\033[1;31m[deploy:FAIL]\033[0m 未知参数: %s\n' "$_a" >&2; usage >&2; exit 2 ;;
esac
done
# 构建产物(持久路径,均已 gitignore)
@@ -305,7 +338,8 @@ if [ "$VERIFY_MANIFEST" = "1" ]; then
exit 0
fi
if [ "${1:-}" = "--verify-only" ]; then
# --verify-only:只跑全量校验(不构建/不安装/不重启)—— 反例测试/人工体检用
if [ "$VERIFY_ONLY" = "1" ]; then
do_verify
exit 0
fi
@@ -324,6 +358,24 @@ if [ "$MARK_APPROVED" = "1" ]; then
exit 0
fi
# --dry-run(t_debe2002 AC11):跑前置闸门 + 打印将执行的动作后退出 —— 不写文件/不停止/不启动。
# 先跑 preflight_reviewed_commits + preflight_clean_tree(纯只读检查):若部署会被闸门拦下,
# 这里就真实报出(die exit=1),让 dry-run 成为「这次部署能否通过」的预览;
# 通过则打印完整动作清单后 exit 0,绝不触碰生产。
if [ "$DRY_RUN" = "1" ]; then
preflight_reviewed_commits
preflight_clean_tree
log "dry-run:以下为完整部署将执行的动作(本次不写/不停/不启)——"
log " · 构建: go build → $BUILD_GO"
log " · 构建: cargo build --release → $BUILD_RUST"
log " · 停止: $SVC_GO + $SVC_RUST"
log " · install: → $INSTALL_GO + $INSTALL_RUST"
log " · daemon-reload + 启动: $SVC_GO + $SVC_RUST"
log " · 校验: 服务 active / 无(deleted) inode / 运行sha=构建sha / /health=200 / bi-temporal e2e / 自证版本"
log "dry-run 结束(未执行任何部署动作)"
exit 0
fi
do_build
do_install
do_verify