e6c44c9bf8
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 3s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Style (pull_request) Has been skipped
CI/CD Pipeline / Validate - Security (pull_request) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 4m59s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 5m16s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 2m15s
CI/CD Pipeline / CI Gate (pull_request) Successful in 3s
AI Code Review / AI Code Review (pull_request) Successful in 7m12s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 7m25s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 7m55s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Failing after 0s
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Check push changed paths (push) Has been skipped
CI/CD Pipeline / Validate - Style (push) Failing after 0s
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Failing after 0s
CI/CD Pipeline / Validate - Security (push) Failing after 0s
CI/CD Pipeline / Frontend Unit Tests (push) Failing after 1s
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (push) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (push) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (push) Has been skipped
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Failing after 15s
CI/CD Pipeline / Unit Tests (push) Failing after 16s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com> Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
178 lines
5.1 KiB
Bash
178 lines
5.1 KiB
Bash
#!/usr/bin/env bash
|
|
# ===========================================================
|
|
# config_diff_check.sh — 对比渲染 .env 与服务器当前 .env
|
|
# ===========================================================
|
|
# 用法: scripts/config_diff_check.sh <rendered_file> <current_file>
|
|
#
|
|
# 输出:
|
|
# + ADDED 渲染文件有、当前文件没有(新增配置)
|
|
# - REMOVED 当前文件有、渲染文件没有(将被删除)
|
|
# ~ CHANGED 两边都有但值不同(将被覆盖)
|
|
#
|
|
# 敏感值脱敏:KEY/SECRET/PASSWORD/TOKEN/URL 类变量只显示前4字符+***
|
|
# 退出码: 始终返回 0(仅告警,不阻塞部署)
|
|
# ===========================================================
|
|
set -u
|
|
|
|
RENDERED_FILE="${1:-}"
|
|
CURRENT_FILE="${2:-}"
|
|
|
|
if [ -z "$RENDERED_FILE" ] || [ -z "$CURRENT_FILE" ]; then
|
|
echo "ERROR: 用法: $0 <rendered_file> <current_file>" >&2
|
|
exit 0
|
|
fi
|
|
|
|
if [ ! -f "$RENDERED_FILE" ]; then
|
|
echo "ERROR: 渲染文件不存在: $RENDERED_FILE" >&2
|
|
exit 0
|
|
fi
|
|
|
|
# 判断是否为敏感变量(键名包含以下关键词)
|
|
is_sensitive() {
|
|
local key="$1"
|
|
case "$key" in
|
|
*KEY*|*SECRET*|*PASSWORD*|*TOKEN*|*URL*|*BROKER*|*BACKEND*) return 0 ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
|
|
# 脱敏:敏感值只显示前4字符+***
|
|
mask_value() {
|
|
local key="$1"
|
|
local value="$2"
|
|
if is_sensitive "$key"; then
|
|
if [ ${#value} -le 4 ]; then
|
|
echo "****"
|
|
else
|
|
echo "${value:0:4}***"
|
|
fi
|
|
else
|
|
echo "$value"
|
|
fi
|
|
}
|
|
|
|
# 解析文件为 KEY=VALUE(忽略注释和空行)
|
|
parse_env() {
|
|
local file="$1"
|
|
grep -vE '^\s*#|^\s*$' "$file" 2>/dev/null | while IFS= read -r line; do
|
|
# 只取第一个 = 之前的部分作为 key
|
|
key="${line%%=*}"
|
|
value="${line#*=}"
|
|
# 跳过无效行
|
|
if [ -n "$key" ] && [ "$key" != "$line" ]; then
|
|
echo "${key}=${value}"
|
|
fi
|
|
done
|
|
}
|
|
|
|
echo "=========================================="
|
|
echo " 配置 Diff 检查(检测配置漂移)"
|
|
echo "=========================================="
|
|
echo "渲染文件: $RENDERED_FILE"
|
|
echo "当前文件: $CURRENT_FILE"
|
|
echo ""
|
|
|
|
# 解析两个文件
|
|
if [ ! -f "$CURRENT_FILE" ] || [ ! -s "$CURRENT_FILE" ]; then
|
|
# 服务器 .env 不存在或为空(首次部署)
|
|
echo "⚠️ 服务器 .env 不存在或为空(可能是首次部署)"
|
|
echo " 所有配置项将标记为 ADDED"
|
|
echo ""
|
|
|
|
added=0
|
|
while IFS='=' read -r key value; do
|
|
[ -z "$key" ] && continue
|
|
masked=$(mask_value "$key" "$value")
|
|
echo " + ADDED ${key}=${masked}"
|
|
added=$((added + 1))
|
|
done < <(parse_env "$RENDERED_FILE")
|
|
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " 汇总: 新增 ${added} 项 | 删除 0 项 | 变更 0 项 | 无变化 0 项"
|
|
echo "=========================================="
|
|
exit 0
|
|
fi
|
|
|
|
# 用临时文件存储解析结果
|
|
tmp_rendered=$(mktemp)
|
|
tmp_current=$(mktemp)
|
|
trap "rm -f $tmp_rendered $tmp_current" EXIT
|
|
|
|
parse_env "$RENDERED_FILE" | sort > "$tmp_rendered"
|
|
parse_env "$CURRENT_FILE" | sort > "$tmp_current"
|
|
|
|
added=0
|
|
removed=0
|
|
changed=0
|
|
unchanged=0
|
|
|
|
echo "--- 新增配置(渲染文件有、当前文件无)---"
|
|
# 找 ADDED:渲染文件有但当前文件没有的 key
|
|
while IFS='=' read -r key value; do
|
|
[ -z "$key" ] && continue
|
|
current_line=$(grep -m1 "^${key}=" "$tmp_current" 2>/dev/null || true)
|
|
if [ -z "$current_line" ]; then
|
|
masked=$(mask_value "$key" "$value")
|
|
echo " + ADDED ${key}=${masked}"
|
|
added=$((added + 1))
|
|
fi
|
|
done < "$tmp_rendered"
|
|
|
|
if [ "$added" -eq 0 ]; then
|
|
echo " (无)"
|
|
fi
|
|
|
|
echo ""
|
|
echo "--- 删除配置(当前文件有、渲染文件无)---"
|
|
# 找 REMOVED:当前文件有但渲染文件没有的 key
|
|
while IFS='=' read -r key value; do
|
|
[ -z "$key" ] && continue
|
|
rendered_line=$(grep -m1 "^${key}=" "$tmp_rendered" 2>/dev/null || true)
|
|
if [ -z "$rendered_line" ]; then
|
|
masked=$(mask_value "$key" "$value")
|
|
echo " - REMOVED ${key}=${masked}"
|
|
removed=$((removed + 1))
|
|
fi
|
|
done < "$tmp_current"
|
|
|
|
if [ "$removed" -eq 0 ]; then
|
|
echo " (无)"
|
|
fi
|
|
|
|
echo ""
|
|
echo "--- 变更配置(两边都有但值不同)---"
|
|
# 找 CHANGED:两边都有但值不同
|
|
while IFS='=' read -r key value; do
|
|
[ -z "$key" ] && continue
|
|
current_line=$(grep -m1 "^${key}=" "$tmp_current" 2>/dev/null || true)
|
|
if [ -n "$current_line" ]; then
|
|
current_value="${current_line#*=}"
|
|
if [ "$value" != "$current_value" ]; then
|
|
masked_new=$(mask_value "$key" "$value")
|
|
masked_old=$(mask_value "$key" "$current_value")
|
|
echo " ~ CHANGED ${key}: ${masked_old} → ${masked_new}"
|
|
changed=$((changed + 1))
|
|
else
|
|
unchanged=$((unchanged + 1))
|
|
fi
|
|
fi
|
|
done < "$tmp_rendered"
|
|
|
|
if [ "$changed" -eq 0 ]; then
|
|
echo " (无)"
|
|
fi
|
|
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " 汇总: 新增 ${added} 项 | 删除 ${removed} 项 | 变更 ${changed} 项 | 无变化 ${unchanged} 项"
|
|
echo "=========================================="
|
|
|
|
if [ "$added" -gt 0 ] || [ "$removed" -gt 0 ] || [ "$changed" -gt 0 ]; then
|
|
echo "⚠️ 检测到配置漂移,请确认以上变更是否符合预期"
|
|
else
|
|
echo "✅ 配置无漂移,与服务器当前配置一致"
|
|
fi
|
|
|
|
exit 0
|