Files
GovAI/go-upgrade.sh
T
selfrelease 60b4c3244e security: P1 Cookie Secure标志 + P0 Go补丁升级脚本 + 第三轮审计报告
- P1: auth.go 8处Cookie补充Secure:true+SameSite,gosec 84→78
- P0: 新增go-upgrade.sh (check/upgrade/status三模式)
- docs: 安全审计报告第十一章 - SAST/CVE/CWE审计结果
2026-06-26 15:53:05 +08:00

224 lines
7.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# ============================================================
# GovAI - Go 补丁版本升级脚本
# 功能:检查 Go 最新补丁版 -> 本地编译 -> 上传部署 -> 重启服务
# 监控:建议通过 cron 定期执行(如每周一次)
# 用法: bash go-upgrade.sh [check|upgrade|status]
# check - 仅检查版本(默认)
# upgrade - 执行完整升级流程
# status - 查看当前 Go 版本和服务状态
# ============================================================
set -euo pipefail
SERVER="${SERVER:-govai-root}"
REMOTE_DIR="/opt/govai"
REMOTE_SERVER_BIN="$REMOTE_DIR/server/server"
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
SERVER_GO_VERSION="${SERVER_GO_VERSION:-1.25.0}"
GREEN='\033[0;32m'; BLUE='\033[0;34m'; RED='\033[0;31m'; YELLOW='\033[0;33m'; NC='\033[0m'
log() { echo -e "${GREEN}[✓]${NC} $1"; }
step() { echo -e "\n${BLUE}==== $1 ====${NC}"; }
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
err() { echo -e "${RED}[✗]${NC} $1"; exit 1; }
# ---- 当前版本信息 ----
CURRENT_GO_VERSION=$(go version 2>/dev/null | sed 's/go version //' | awk '{print $1}')
MAJOR_MINOR=$(echo "$CURRENT_GO_VERSION" | sed 's/\.[0-9]*$//')
echo "当前本地 Go 版本: $CURRENT_GO_VERSION"
echo "服务器 Go 版本: $SERVER_GO_VERSION"
# ---- 获取 Go 官方最新补丁版本 ----
fetch_latest_patch() {
local major_minor="$1"
# 从 Go 官方 dl 页面解析最新补丁版本
# 例如: go1.25.11, go1.24.5 等
local url="https://go.dev/dl/?mode=json&include=all"
local latest
latest=$(curl -sL "$url" 2>/dev/null | \
python3 -c "
import sys, json
data = json.load(sys.stdin)
current = '$major_minor'
for p in data:
v = p.get('version','')
if v.startswith('go' + current + '.'):
print(v)
break
" 2>/dev/null) || true
echo "$latest"
}
# ---- 版本比较 ----
# 返回 0 表示有更新,返回 1 表示已是最新
is_update_available() {
local current="$1"
local latest="$2"
[ -n "$latest" ] && [ "$latest" != "$current" ]
}
# ---- 检查模式 ----
do_check() {
step "检查 Go 版本更新"
echo ""
local latest
latest=$(fetch_latest_patch "$MAJOR_MINOR")
echo " 本地当前版本: $CURRENT_GO_VERSION"
echo " $MAJOR_MINOR 系列最新: $latest"
echo ""
if is_update_available "$CURRENT_GO_VERSION" "$latest"; then
echo " 发现新版本: $CURRENT_GO_VERSION$latest"
echo " 建议执行: bash go-upgrade.sh upgrade"
return 0
else
echo " ✅ 当前版本已是最新"
return 1
fi
}
# ---- 升级模式 ----
do_upgrade() {
local latest
latest=$(fetch_latest_patch "$MAJOR_MINOR")
if ! is_update_available "$CURRENT_GO_VERSION" "$latest"; then
echo "已是最新版本,无需升级"
return 0
fi
local new_patch="${latest#go}"
step "Go 升级: $CURRENT_GO_VERSION → go$new_patch"
# 1. 安装新版本 Go
echo ""
log "下载 Go $new_patch..."
cd /tmp
local go_archive="go$new_patch.darwin-arm64.tar.gz"
local download_url="https://go.dev/dl/$go_archive"
# 检测架构
local arch
case "$(uname -m)" in
x86_64) arch="darwin-amd64" ;;
arm64|aarch64) arch="darwin-arm64" ;;
*) err "不支持的架构: $(uname -m)" ;;
esac
go_archive="go$new_patch.$arch.tar.gz"
download_url="https://go.dev/dl/$go_archive"
if [ -f "/usr/local/go/bin/go" ]; then
if /usr/local/go/bin/go version 2>/dev/null | grep -q "$new_patch"; then
echo "目标版本已安装"
else
curl -sL "$download_url" -o "go.tar.gz"
rm -rf /usr/local/go
tar -C /usr/local -xzf go.tar.gz
rm -f go.tar.gz
fi
else
curl -sL "$download_url" -o "go.tar.gz"
tar -C /usr/local -xzf go.tar.gz
rm -f go.tar.gz
fi
local new_go="/usr/local/go/bin/go"
echo " 新版本: $($new_go version)"
# 2. 备份当前服务器二进制
step "备份服务器二进制"
local backup_file="server.bak.$(date '+%Y%m%d%H%M%S')"
ssh "$SERVER" "cp $REMOTE_SERVER_BIN $REMOTE_DIR/$backup_file"
# 3. 本地编译
step "编译新版本二进制"
local dist_dir="$PROJECT_DIR/dist"
mkdir -p "$dist_dir"
log "编译 Go 后端 (linux/amd64)..."
export PATH="/usr/local/go/bin:$PATH"
export GOROOT="/usr/local/go"
cd "$PROJECT_DIR/server"
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOROOT="/usr/local/go" go build \
-ldflags="-s -w" \
-o "$dist_dir/server" ./cmd/server/
local binary_size
binary_size=$(ls -lh "$dist_dir/server" 2>/dev/null | awk '{print $5}')
log "编译完成: dist/server ($binary_size)"
# 4. 上传
step "上传到服务器"
ssh $SERVER "systemctl stop govai-api 2>/dev/null || true"
ssh $SERVER "cp $REMOTE_SERVER_BIN $REMOTE_DIR/server.bak.pre-upgrade"
cat "$dist_dir/server" | ssh $SERVER "cat > $REMOTE_SERVER_BIN.tmp && mv $REMOTE_SERVER_BIN.tmp $REMOTE_SERVER_BIN && chmod +x $REMOTE_SERVER_BIN"
log "上传完成"
# 5. 重启服务
step "重启服务"
ssh $SERVER "systemctl start govai-api && sleep 2 && systemctl status govai-api --no-pager | head -5"
# 6. 验证
step "验证服务"
if ssh $SERVER "curl -sf http://localhost:8080/api/v1/store/featured -o /dev/null"; then
log "API 服务正常"
else
err "API 服务异常,请检查: ssh $SERVER 'journalctl -u govai-api -n 30'"
fi
# 7. 记录
local upgrade_log="$PROJECT_DIR/.go-upgrade-log"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $CURRENT_GO_VERSION → go$new_patch" >> "$upgrade_log"
echo ""
echo -e "${GREEN}════════════════════════════════════════${NC}"
echo -e "${GREEN} 升级完成!${NC}"
echo -e "${GREEN} Go: $CURRENT_GO_VERSION → go$new_patch${NC}"
echo -e "${GREEN}════════════════════════════════════════${NC}"
}
# ---- 状态模式 ----
do_status() {
step "版本状态"
echo " 本地 Go 版本: $CURRENT_GO_VERSION"
ssh $SERVER "echo ' 服务器 Go 版本: $SERVER_GO_VERSION'; echo ' GovAI 二进制:'; ssh $SERVER 'ls -lh $REMOTE_SERVER_BIN 2>/dev/null || echo 不存在'"
echo ""
local latest
latest=$(fetch_latest_patch "$MAJOR_MINOR" 2>/dev/null)
echo " $MAJOR_MINOR 系列最新: ${latest:-无法获取}"
echo ""
# 检查 govulncheck
if command -v ~/go/bin/govulncheck &>/dev/null; then
echo " govulncheck 已知漏洞: $(cd "$PROJECT_DIR/server" && ~/go/bin/govulncheck ./... 2>&1 | grep -c '^Vulnerability #' || echo 0)"
fi
}
# ---- 主流程 ----
ACTION="${1:-check}"
case "$ACTION" in
check)
do_check
;;
upgrade)
do_upgrade
;;
status)
do_status
;;
*)
echo "用法: bash go-upgrade.sh [check|upgrade|status]"
echo ""
echo " check - 检查 Go 版本更新(默认)"
echo " upgrade - 执行完整升级:下载 -> 编译 -> 上传 -> 重启"
echo " status - 查看当前 Go 版本和补丁状态"
exit 1
;;
esac