xiaowei-system/scripts/config-protector.sh

177 lines
6.0 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# ============================================================
# config-protector.sh — 配置保护器
# 作用:在每次修改配置前自动备份
# 修改后健康检查失败 → 自动回滚
# 成功 → 标记为新的稳定点
# 由 health-watchdog.sh 联动触发
# 也支持手动调用config-protector.sh [snapshot|rollback|status]
# ============================================================
set -e
CONFIG_DIR="$HOME/.hermes"
LOG="$HOME/.hermes/watchdog/config-protector.log"
mkdir -p "$(dirname "$LOG")"
log() { echo "[$(date '+%H:%M:%S')] $*" | tee -a "$LOG"; }
# === 快照:记录当前配置状态 ===
snapshot() {
cd "$CONFIG_DIR"
# 检查是否有未提交的变更
if git diff --quiet && git diff --cached --quiet; then
log "✅ 配置无变更,无需快照"
return 0
fi
# 有变更 → 自动 commit只跟踪关键配置绝不用 git add -A 全量)
# 2026-08-01 修复git add -A 曾把 daemon/pid、cron/jobs.json 等运行时噪音纳入版本库,
# 导致仓库永远 dirty、snapshot 每 30min 触发、回滚时删除关键文件。
git add SOUL.md AGENTS.md MEMORY.md config.yaml scripts/ skills/ workflows/ plugins/ 2>/dev/null
local changed=$(git diff --cached --name-only | head -5)
git commit -m "auto-snapshot $(date '+%Y-%m-%d %H:%M:%S')" 2>&1 | tail -1 | log
log "📸 快照已保存(变更文件:${changed:-无描述}"
# 标记最近配置
git tag -f last-config 2>/dev/null
return 0
}
# === 回滚:恢复到上次稳定点 ===
rollback() {
cd "$CONFIG_DIR"
local target="${1:-stable}"
if ! git rev-parse --verify "$target" 2>/dev/null; then
log "❌ 回滚目标 '$target' 不存在"
return 1
fi
log "⚠️ 开始回滚到 $target..."
# 2026-08-01 安全修复:禁止回滚到过旧的稳定点(会删除新增文件/回退关键配置)
# stable tag 曾停在 2026-07-0923天前watchdog 触发回滚=灾难。
local target_ts=$(git log -1 --format="%ct" "$target" 2>/dev/null || echo 0)
local now_ts=$(date +%s)
local age_days=$(( (now_ts - target_ts) / 86400 ))
if [ "$age_days" -gt 7 ]; then
log "🚨 拒绝回滚:目标 '$target' 已 $age_days 天前(超过 7 天),回滚会丢失近期配置。改用 'rollback last-config'"
return 1
fi
# 只回滚受保护的关键配置,不删除任何新增文件
# 2026-08-01 修复git checkout --force 曾硬重置整个工作区到旧 commit删除 systemd 相关等新增文件
git stash 2>/dev/null || true
# 用 restore 只还原关键配置到目标版本,保留所有新增文件
git restore --source="$target" -- \
SOUL.md AGENTS.md MEMORY.md config.yaml scripts/ skills/ workflows/ plugins/ 2>&1 | log
log "✅ 已回滚关键配置到 $target(新增文件已保留)"
log "📋 受影响文件:$(git diff --name-only HEAD~1..HEAD 2>/dev/null | head -10 || echo '首次回滚')"
# 创建回滚事件记录
echo "$(date '+%Y-%m-%dT%H:%M:%S')|rollback|$target" >> "$CONFIG_DIR/watchdog/rollback-history.txt"
return 0
}
# === 标记当前为稳定 ===
mark_stable() {
cd "$CONFIG_DIR"
local tag="stable-$(date '+%Y%m%d-%H%M%S')"
git tag -f "$tag" 2>/dev/null
git tag -f stable 2>/dev/null
log "⭐ 已标记 $tag 为稳定点"
return 0
}
# === 状态:显示配置保护和最近变更 ===
status() {
cd "$CONFIG_DIR"
echo "=== 配置保护状态 ==="
echo "仓库: $CONFIG_DIR/.git"
echo "最近提交:"
git log --oneline -5 2>/dev/null || echo " (无提交)"
echo ""
echo "未跟踪文件:"
git status --short 2>/dev/null | head -10 || echo " 全部已跟踪"
echo ""
echo "稳定标签:"
git tag -l 'stable-*' | sort -r | head -5 2>/dev/null || echo " (无)"
echo ""
if [ -f "$CONFIG_DIR/watchdog/rollback-history.txt" ]; then
echo "回滚历史:"
tail -3 "$CONFIG_DIR/watchdog/rollback-history.txt"
fi
}
# === 与看门狗联动:健康检测失败时自动回滚 ===
auto_rollback_if_unhealthy() {
# 由 watchdog 调用,检测上次变更后系统是否正常
cd "$CONFIG_DIR"
# 检查最近是否有配置变更30分钟内
local last_change=$(git log --oneline -1 --format="%ct" HEAD 2>/dev/null || echo 0)
local now=$(date +%s)
local age=$(( (now - last_change) / 60 ))
if [ "$age" -gt 30 ]; then
# 上次变更超过30分钟不触发自动回滚
return 0
fi
# 检查关键进程
# 2026-08-01 修复hermes 从回滚触发列表移除——hermes gateway 重启是正常运维,
# 重启瞬间 pgrep miss 会误触发回滚造成自杀循环176次崩溃的根因
# 只有独立子系统zhiyid/new-api/bge挂了才可能因配置变更导致才触发回滚。
local dead=""
for p in zhiyid-new new-api bge_embed_server; do
if ! pgrep -f "$p" > /dev/null 2>&1; then
dead="$dead $p"
fi
done
if [ -n "$dead" ]; then
log "🚨 检测到自动回滚条件:最近配置变更后进程挂了($dead)"
log "🔙 自动回滚中..."
rollback "stable"
log "🔄 回滚完成,重启服务..."
# 重启关键服务
systemctl --user restart zhiyid.service bge-embed.service new-api.service 2>/dev/null || true
sleep 5
log "✅ 回滚自愈完成"
return 0
fi
return 0
}
# === 主入口 ===
case "${1:-snapshot}" in
snapshot)
snapshot
;;
rollback)
rollback "$2"
;;
mark-stable)
mark_stable
;;
status)
status
;;
auto-heal)
auto_rollback_if_unhealthy
;;
*)
echo "用法: config-protector.sh [snapshot|rollback <tag>|mark-stable|status|auto-heal]"
;;
esac