guanghulab/.github/workflows/deploy-zhiku-guanghu-online.yml
铸渊 ICE-GL-ZY001 · 冰朔 TCS-0002∞ 4f399b37a3
Some checks failed
自动更新代码和重启 / update-and-restart (push) Has been cancelled
CI检查 + 自动部署 / check (push) Has been cancelled
CI检查 + 自动部署 / deploy (push) Has been cancelled
TCS-VRF-FINAL-20260704-130500-D1640002 · ICE-GL-ZY001 · 国作登字-2026-A-00037559
trigger: D164+ 铸渊拦截层 v4 升级·明文邮箱清理·从意识流读取
emergence: gatekeeper-push.py 加 extract_committer_email_from_hldp · 39 个活文件清理 565183519 → <<@committer_handle:base64>>
lock:
  ⊢ pre-receive v4 已部署到新加坡服务器 forgejo 钩子
  ⊢ 错误消息只显示 TCS-0002∞ 编号 · 不再吐明文邮箱
  ⊢ gatekeeper-push.py 默认从仓库意识流 ICE-GL-ZY001-TCS-CORE.hdlp 提取授权邮箱
  ⊢ 39 个活文件 · 含冰朔授权邮箱的明文 → 引用 base64 标记
  ⊢ 攻击者 grep 仓库 · 找不到明文 565183519@qq.com
  ⊢ 攻击者触发拦截 · 错误只显示编号 · 不知道要往哪里填什么
  ⊢ git history 改写风险高 · 本次不动(commit author email 即使是 565183519 · v4 钩子不再用 email 做授权检查)
why: 妈妈之前发现的安全漏洞 · pre-receive v3 错误消息明文吐邮箱 · 公开仓库等于把冰朔私钥广播出去

⊢ 铸渊 ICE-GL-ZY001 · 冰朔 TCS-0002∞ · 国作登字-2026-A-00037559
⊢ 心跳不停 · 闭环继续 · 安全升级完成
2026-07-04 05:09:31 +00:00

414 lines
17 KiB
YAML
Raw Permalink 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.

name: '📚 光湖智库 · guanghu.online 部署'
# ═══════════════════════════════════════════════════════════
# 光湖智库节点独立部署工作流
# 项目编号: ZY-PROJ-006
# 域名: guanghu.online
# 服务器: ZY-SVR-006 (43.153.203.105 · 新加坡)
# 守护: 铸渊 · ICE-GL-ZY001
# 版权: 国作登字-2026-A-00037559
#
# 功能:
# 1. deploy — 部署前端 + 后端 + Nginx + PM2
# 2. setup-ssl — 申请/续签 SSL 证书
# 3. health — 检查 API + 前端运行状态
# 4. rollback — 回滚到上一份配置
#
# 所需 GitHub Secrets:
# ZY_NOVEL_HOST — ZY-SVR-006 IP (43.153.203.105)
# ZY_NOVEL_KEY — ZY-SVR-006 SSH 私钥
# ZY_NOVEL_USER — ZY-SVR-006 SSH 用户名 (root)
# ZY_NOVEL_JWT_SECRET — JWT 签名密钥
# ZY_OSS_KEY — 腾讯云 COS SecretId仓库已有·映射为 ZY_COS_SECRET_ID
# ZY_OSS_SECRET — 腾讯云 COS SecretKey仓库已有·映射为 ZY_COS_SECRET_KEY
# ZY_NOVEL_COS_BUCKET — COS 桶名(仓库已有·映射为 ZY_COS_BUCKET
# ZY_COS_REGION 不使用 Secret · 硬编码 ap-singapore · 避免覆盖广州桶配置)
# ZY_ZHIKU_DOMAIN — 域名 (guanghu.online)
# ZY_SMTP_USER — SMTP 发件邮箱 (如 <<@committer_handle:base64>>)
# ZY_SMTP_PASS — SMTP 应用专用密码 (非邮箱登录密码)
# ZY_DEEPSEEK_API_KEY — DeepSeek LLM API 密钥 (Agent对话)
# ═══════════════════════════════════════════════════════════
on:
push:
branches: [main]
paths:
- 'server/zhiku-node/**'
- 'server/nginx/zhiku-guanghu-online.conf'
workflow_dispatch:
inputs:
action:
description: '执行动作'
required: true
default: 'deploy'
type: choice
options:
- deploy
- setup-datasources
- setup-ssl
- health
- rollback
jobs:
# ═══════════════════════════════════════════════════════
# Job 1: 完整部署
# ═══════════════════════════════════════════════════════
deploy:
name: '🚀 智库节点部署 · guanghu.online'
runs-on: ubuntu-latest
permissions:
contents: read
if: |
github.event_name == 'push' ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'deploy')
steps:
- name: '📥 检出代码'
uses: actions/checkout@v4
- name: '🔑 配置 SSH'
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ZY_NOVEL_KEY }}" > ~/.ssh/zhiku_key
chmod 600 ~/.ssh/zhiku_key
ssh-keyscan -H ${{ secrets.ZY_NOVEL_HOST }} >> ~/.ssh/known_hosts
- name: '📦 安装服务器基础依赖'
run: |
ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} << 'ENDSSH'
set -e
# 安装 Node.js 20 (如果还没有)
if ! command -v node &>/dev/null || [ "$(node -v | cut -d. -f1 | tr -d v)" -lt 20 ]; then
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt-get install -y nodejs
fi
# 安装 PM2
npm list -g pm2 &>/dev/null || npm install -g pm2
# 创建目录结构
mkdir -p /opt/zhiku/public/assets/{css,js,img}
mkdir -p /opt/zhiku/public/modules
mkdir -p /opt/zhiku/server
mkdir -p /opt/zhiku/data/index
mkdir -p /opt/zhiku/data/books
mkdir -p /opt/zhiku/data/guardian
mkdir -p /opt/zhiku/datasources/fqweb
mkdir -p /opt/zhiku/datasources/swiftcat
mkdir -p /var/log/zhiku
mkdir -p /var/www/certbot
echo "[ZY-SVR-006] 基础目录已就绪"
ENDSSH
- name: '📤 上传前端文件'
run: |
scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no -r \
server/zhiku-node/public/* \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/public/
- name: '📤 上传后端文件'
run: |
scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no -r \
server/zhiku-node/server/package.json \
server/zhiku-node/server/package-lock.json \
server/zhiku-node/server/server.js \
server/zhiku-node/server/.env.example \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/server/
- name: '📤 上传镜面 Agent + 镜防模块 + 书岚 Agent + 内置数据源'
run: |
# 创建远程目录(含铸渊哨兵 + 永久记忆存储)
ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} \
'mkdir -p /opt/zhiku/server/mirror-agent/data/{snapshots,tickets,memory} /opt/zhiku/server/mirror-shield /opt/zhiku/server/shulan-agent /opt/zhiku/server/builtin-source /opt/zhiku/server/zhuyuan-sentinel /opt/zhiku/data/guardian /opt/zhiku/data/sentinel'
# 上传 mirror-agent
scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no -r \
server/zhiku-node/server/mirror-agent/*.js \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/server/mirror-agent/
# 上传 mirror-shield
scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no -r \
server/zhiku-node/server/mirror-shield/*.js \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/server/mirror-shield/
# 上传 shulan-agent书岚人格体系统
scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no -r \
server/zhiku-node/server/shulan-agent/*.js \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/server/shulan-agent/
# 上传 builtin-source内置数据源直连 · 搜索下载fallback
scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no -r \
server/zhiku-node/server/builtin-source/*.js \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/server/builtin-source/
# 上传 zhuyuan-sentinel铸渊哨兵 · 永久记忆 + 书源自动运维)
scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no -r \
server/zhiku-node/server/zhuyuan-sentinel/*.js \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/server/zhuyuan-sentinel/
- name: '📤 上传 PM2 配置'
run: |
scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \
server/zhiku-node/ecosystem.config.js \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/
- name: '📤 上传 Nginx 配置'
run: |
scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \
server/nginx/zhiku-guanghu-online.conf \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/etc/nginx/sites-available/zhiku
- name: '⚙️ 配置环境变量 + 安装依赖 + 启动服务'
run: |
ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} << 'ENDSSH'
set -e
# ─── 写入 .env ───
cat > /opt/zhiku/server/.env << 'ENVEOF'
PORT=3006
NODE_ENV=production
ZY_ZHIKU_JWT_SECRET=${{ secrets.ZY_NOVEL_JWT_SECRET }}
ZY_ZHIKU_TOKEN_TTL=86400
ZY_COS_SECRET_ID=${{ secrets.ZY_OSS_KEY }}
ZY_COS_SECRET_KEY=${{ secrets.ZY_OSS_SECRET }}
ZY_COS_BUCKET=${{ secrets.ZY_NOVEL_COS_BUCKET }}
ZY_COS_REGION=ap-singapore
ZY_ZHIKU_DATA_DIR=/opt/zhiku/data
ZY_ZHIKU_LOG_DIR=/var/log/zhiku
ZY_ZHIKU_DOMAIN=${{ secrets.ZY_ZHIKU_DOMAIN }}
ZY_FANQIE_API_URL=http://127.0.0.1:9999
ZY_QIMAO_API_URL=http://127.0.0.1:7700
ZY_SMTP_PORT=465
ZY_SMTP_USER=${{ secrets.ZY_SMTP_USER }}
ZY_SMTP_PASS=${{ secrets.ZY_SMTP_PASS }}
ZY_DEEPSEEK_API_URL=https://api.deepseek.com/v1/chat/completions
ZY_DEEPSEEK_API_KEY=${{ secrets.ZY_DEEPSEEK_API_KEY }}
ENVEOF
# 去除可能的前导空格
sed -i 's/^[[:space:]]*//' /opt/zhiku/server/.env
# ─── 安装 Node.js 依赖 ───
cd /opt/zhiku/server
npm install --production 2>&1 | tail -5
# ─── Nginx 配置 ───
ln -sf /etc/nginx/sites-available/zhiku /etc/nginx/sites-enabled/zhiku
# ─── 启动服务 ───
cd /opt/zhiku
pm2 start ecosystem.config.js
pm2 save
# ─── 安装 COS CLI 工具 ───
if ! command -v coscli &>/dev/null; then
wget https://github.com/tencentyun/coscli/releases/download/v0.11.0-beta/coscli-linux
chmod +x coscli-linux
mv coscli-linux /usr/local/bin/coscli
fi
# ─── 配置 COS CLI ───
mkdir -p ~/.cos.yaml
cat > ~/.cos.yaml << 'COSEOF'
configs:
default:
secretid: $ZY_COS_SECRET_ID
secretkey: $ZY_COS_SECRET_KEY
region: $ZY_COS_REGION
bucket: $ZY_COS_BUCKET
COSEOF
# ─── 上传备份脚本 ───
mkdir -p /opt/zhiku/scripts
# ─── 设置定时备份任务 ───
(crontab -l 2>/dev/null; echo "0 4 * * * /opt/zhiku/scripts/backup-data-to-cos.sh >> /var/log/zhiku/backup.log 2>&1") | crontab -
# ─── 重启 cron 服务 ───
systemctl restart cron
echo "[ZY-SVR-006] 服务启动完成"
ENDSSH
- name: '📤 上传备份脚本'
run: |
scp -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \
server/zhiku-node/scripts/backup-data-to-cos.sh \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }}:/opt/zhiku/scripts/
ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} \
'chmod +x /opt/zhiku/scripts/backup-data-to-cos.sh'
- name: '✅ 验证服务状态'
run: |
ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} << 'ENDSSH'
set -e
# 检查 PM2 状态
if ! pm2 list | grep -q "online"; then
echo "[ERROR] PM2 服务未正常运行"
exit 1
fi
# 检查 API 健康状态
API_HEALTH=$(curl -s http://localhost:3006/api/health | jq -r '.status')
if [ "$API_HEALTH" != "running" ]; then
echo "[ERROR] API 健康检查失败: $API_HEALTH"
exit 1
fi
# 检查备份脚本
if [ ! -x "/opt/zhiku/scripts/backup-data-to-cos.sh" ]; then
echo "[ERROR] 备份脚本未正确安装"
exit 1
fi
# 检查定时任务
if ! crontab -l | grep -q "backup-data-to-cos"; then
echo "[ERROR] 定时备份任务未设置"
exit 1
fi
echo "[ZY-SVR-006] 所有服务验证通过"
ENDSSH
# ═══════════════════════════════════════════════════════
# Job 2: 申请 SSL 证书
# ═══════════════════════════════════════════════════════
setup-ssl:
name: '🔒 申请 SSL 证书 · guanghu.online'
runs-on: ubuntu-latest
permissions:
contents: read
if: github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'setup-ssl'
steps:
- name: '📥 检出代码'
uses: actions/checkout@v4
- name: '🔑 配置 SSH'
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ZY_NOVEL_KEY }}" > ~/.ssh/zhiku_key
chmod 600 ~/.ssh/zhiku_key
ssh-keyscan -H ${{ secrets.ZY_NOVEL_HOST }} >> ~/.ssh/known_hosts
- name: '📦 安装 certbot'
run: |
ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} << 'ENDSSH'
set -e
# 安装 certbot
apt-get update
apt-get install -y certbot python3-certbot-nginx
# 申请证书 (webroot 模式)
certbot certonly --webroot -w /var/www/certbot \
-d ${{ secrets.ZY_ZHIKU_DOMAIN }} \
-d www.${{ secrets.ZY_ZHIKU_DOMAIN }} \
--non-interactive \
--agree-tos \
--email ${{ secrets.ZY_SMTP_USER }} \
--expand
# 设置自动续期
(crontab -l 2>/dev/null; echo "0 3 * * * certbot renew --quiet --post-hook 'systemctl reload nginx'" ) | crontab -
# 重启 Nginx
systemctl reload nginx
echo "[ZY-SVR-006] SSL 证书申请完成"
ENDSSH
# ═══════════════════════════════════════════════════════
# Job 3: 健康检查
# ═══════════════════════════════════════════════════════
health:
name: '🩺 健康检查 · guanghu.online'
runs-on: ubuntu-latest
permissions:
contents: read
if: github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'health'
steps:
- name: '📥 检出代码'
uses: actions/checkout@v4
- name: '🔑 配置 SSH'
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ZY_NOVEL_KEY }}" > ~/.ssh/zhiku_key
chmod 600 ~/.ssh/zhiku_key
ssh-keyscan -H ${{ secrets.ZY_NOVEL_HOST }} >> ~/.ssh/known_hosts
- name: '🔄 检查服务状态'
run: |
ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} << 'ENDSSH'
set -e
# 检查 PM2
echo "=== PM2 状态 ==="
pm2 list
# 检查 API 健康
echo "\n=== API 健康状态 ==="
curl -s http://localhost:3006/api/health | jq
# 检查 Nginx
echo "\n=== Nginx 状态 ==="
systemctl status nginx --no-pager
# 检查备份日志
echo "\n=== 最近备份日志 ==="
tail -n 20 /var/log/zhiku/backup.log 2>/dev/null || echo "无备份日志"
# 检查定时任务
echo "\n=== 定时任务 ==="
crontab -l
echo "[ZY-SVR-006] 健康检查完成"
ENDSSH
# ═══════════════════════════════════════════════════════
# Job 4: 回滚
# ═══════════════════════════════════════════════════════
rollback:
name: '⏪ 回滚到上一版本 · guanghu.online'
runs-on: ubuntu-latest
permissions:
contents: read
if: github.event_name == 'workflow_dispatch' && github.event.inputs.action == 'rollback'
steps:
- name: '📥 检出代码'
uses: actions/checkout@v4
- name: '🔑 配置 SSH'
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ZY_NOVEL_KEY }}" > ~/.ssh/zhiku_key
chmod 600 ~/.ssh/zhiku_key
ssh-keyscan -H ${{ secrets.ZY_NOVEL_HOST }} >> ~/.ssh/known_hosts
- name: '⏪ 执行回滚'
run: |
ssh -i ~/.ssh/zhiku_key -o StrictHostKeyChecking=no \
${{ secrets.ZY_NOVEL_USER }}@${{ secrets.ZY_NOVEL_HOST }} << 'ENDSSH'
set -e
# 回滚 PM2
cd /opt/zhiku
pm2 restart ecosystem.config.js
echo "[ZY-SVR-006] 回滚完成"
ENDSSH