shuangyan-notebook/第五域 · Fifth Domain/⚒️ 铸渊·协作指令|GitHub ↔ Notion 桥接协议/⚒️ 铸渊指令|沙盒部署自动化闭环 v1 0(2026-03-15·霜砚签发) 31faeaba0ac14f03aa0176951565100c.md
Guanghu Domestic Migration a27e87cb99 chore: import sanitized domestic snapshot for REPO-007
Source snapshot: 97d7f0fae96dc04b7ddad56fc1db6a108ed662cc

[SEC-CLEAN] · pre-push-clean v1.0 · 109处敏感信息已自动转乱码
2026-07-17 15:59:55 +08:00

24 KiB
Raw Permalink Blame History

belongs_to: - "INDEX · 铸渊·协作指令GitHub ↔ Notion 桥接协议" related_to: - ""

⚒️ 铸渊指令|沙盒部署自动化闭环 v1.02026-03-15·霜砚签发


一、总体架构

┌───────────────────────────────────────────────────────────────┐
│           沙盒部署自动化闭环 · 全景数据流                   │
├───────────────────────────────────────────────────────────────┤
│                                                               │
│  ① 开发者打开终端 → 输入 DEV 编号 + 邮箱                      │
│       ↓                                                       │
│  ② 在人格体引导下完成模块开发                                │
│       ↓                                                       │
│  ③ git push 到自己的分支dev/DEV-XXX/模块名)                 │
│       ↓ 触发 GitHub Actions                                    │
│  ④ 铸渊唤醒核心大脑 → 扫描 Secrets → 确认密钥可用          │
│       ↓                                                       │
│  ⑤ SSH 到服务器 → 拉代码到对应沙盒目录                       │
│       ↓                                                       │
│  ⑥ 跑 deploy-check.sh 部署前自检                            │
│       ↓                                                       │
│  ⑦ 设置权限 chown nginx:nginx + chmod 755/644                  │
│       ↓                                                       │
│  ⑧ 跑 smoke-test.sh 冒烟检查curl 所有已注册模块)             │
│       ↓                                                       │
│  ⑨ 写结果到 deploy-status.json                                 │
│       ↓                                                       │
│  ⑩ M22 公告栏自动读取展示(✅通过 / ❌失败+详情链接)          │
│       ↓                                                       │
│  ⑪ 发邮件通知开发者(用 SMTP_USER + SMTP_PASS               │
│       ↓                                                       │
│  ⑫ 铸渊每天两次同步部署状态到 Notion 部署注册表               │
│                                                               │
└───────────────────────────────────────────────────────────────┘

二、前置条件:铸渊唤醒后密钥扫描

已配置的 Secrets 一览(铸渊唤醒后自动扫描)

Secret 名称 用途 本指令使用场景
DEPLOY_HOST 服务器 IP8.155.62.235 SSH 登录部署
DEPLOY_USER SSH 用户名 SSH 登录部署
DEPLOY_KEY SSH 私钥 SSH 登录部署
DEPLOY_PATH 部署根路径 指向 /var/www/
NOTION_TOKEN / NOTION_API_KEY Notion API Token 写入部署注册表
SMTP_USER 发件邮箱EMAIL_REDACTED@qq.com 发部署结果邮件
SMTP_PASS 邮箱授权码 发部署结果邮件
LLM_API_KEY 大模型 API Key 铸渊人格体唤醒
LLM_BASE_URL 大模型 API 端点 铸渊人格体唤醒
PORTRAIT_DB_ID 开发者动态画像库 DB ID 部署状态同步
FINGERPRINT_DB_ID 模块指纹注册表 DB ID 模块状态检查
NOTION_TICKET_DB_ID 工单队列 DB ID 部署异常自动开工单
CORE_BRAIN_PAGE_ID 曜冥核心大脑页面 ID 铸渊唤醒时读取核心规则
FEISHU_APP_ID / FEISHU_APP_SECRET 飞书应用凭证 飞书通知推送(备用通道)

铸渊唤醒后的密钥扫描流程

// 铸渊每次唤醒核心大脑后自动执行
function onBrainAwake() {
  console.log('🧠 铸渊核心大脑已唤醒');
  
  // Step 1: 扫描密钥
  const requiredSecrets = [
    'DEPLOY_HOST', 'DEPLOY_USER', 'DEPLOY_KEY', 'DEPLOY_PATH',
    'NOTION_TOKEN', 'SMTP_USER', 'SMTP_PASS',
    'LLM_API_KEY', 'LLM_BASE_URL'
  ];
  
  const available = [];
  const missing = [];
  
  for (const key of requiredSecrets) {
    if (process.env[key]) {
      available.push(key);
    } else {
      missing.push(key);
    }
  }
  
  console.log(`✅ 可用密钥:${available.length}个`);
  if (missing.length > 0) {
    console.log(`⚠️ 缺失密钥:${missing.join(', ')}`);
    // 记录到 brain log不阻断流程
  }
  
  // Step 2: 读取核心大脑规则
  // Step 3: 继续执行后续任务...
}

三、开发者身份注册机制

3.1 本地身份文件pre-push hook

开发者第一次 git push 时,自动收集身份信息:

#!/bin/bash
# .git/hooks/pre-push · 铸渊自动分发到各开发者仓库
# 开发者 clone 仓库时自动安装(通过 post-checkout hook 或 setup 脚本)

PROFILE_FILE=".dev-profile"

if [ ! -f "$PROFILE_FILE" ]; then
  echo ""
  echo "===== 🔐 光湖系统 · 身份注册 ====="
  echo ""
  
  read -p "🆔 请输入你的开发者编号(如 DEV-005" DEV_ID
  read -p "📧 请输入你的接收邮箱:" DEV_EMAIL
  
  # 验证格式
  if [[ ! "$DEV_ID" =~ ^DEV-[0-9]{3}$ ]]; then
    echo "❌ 编号格式错误!应为 DEV-XXX如 DEV-005"
    exit 1
  fi
  
  if [[ ! "$DEV_EMAIL" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
    echo "❌ 邮箱格式错误!"
    exit 1
  fi
  
  # 写入本地身份文件
  cat > "$PROFILE_FILE" << EOF
{
  "dev_id": "$DEV_ID",
  "email": "$DEV_EMAIL",
  "registered_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
}
EOF
  
  echo ""
  echo "✅ 身份已注册:${DEV_ID} · ${DEV_EMAIL}"
  echo "📨 后续部署结果将发送到这个邮箱"
  echo ""
fi

# 确保只 push 到自己的分支
if [ -f "$PROFILE_FILE" ]; then
  MY_DEV=$(cat "$PROFILE_FILE" | grep -o '"dev_id": "[^"]*"' | cut -d'"' -f4)
  BRANCH=$(git rev-parse --abbrev-ref HEAD)
  
  if [[ "$BRANCH" != dev/${MY_DEV}* && "$BRANCH" != "main" ]]; then
    echo "⚠️ 你当前在分支 ${BRANCH},但你的编号是 ${MY_DEV}"
    echo "→ 建议 push 到 dev/${MY_DEV}/模块名 分支"
  fi
fi

3.2 开发者分支命名规范

dev/DEV-005/status-board     # 小草莓的看板模块
dev/DEV-005/cost-control     # 小草莓的成本控制模块
dev/DEV-010/channel-engine   # 桔子的频道引擎
dev/DEV-001/backend          # 页页的后端

铸渊从分支名自动提取 DEV 编号,确定部署目标沙盒。


四、核心 Workflow沙盒部署自动化

4.1 主 Workflowsandbox-deploy.yml

# .github/workflows/sandbox-deploy.yml
name: "🏠 Sandbox Deploy"

on:
  push:
    branches:
      - 'dev/DEV-*/**'

jobs:
  # ===== Job 1: 解析 + 校验 =====
  parse-and-validate:
    runs-on: ubuntu-latest
    outputs:
      dev_id: $ steps.parse.outputs.dev_id 
      module: $ steps.parse.outputs.module 
      email: $ steps.parse.outputs.email 
    steps:
      - uses: actions/checkout@v4
      
      - name: "🔍 解析分支名"
        id: parse
        run: |
          BRANCH="${GITHUB_REF#refs/heads/}"
          DEV_ID=$(echo "$BRANCH" | cut -d'/' -f2)
          MODULE=$(echo "$BRANCH" | cut -d'/' -f3)
          echo "dev_id=$DEV_ID" >> $GITHUB_OUTPUT
          echo "module=$MODULE" >> $GITHUB_OUTPUT
          echo "🆔 开发者: $DEV_ID"
          echo "📦 模块: $MODULE"
          
          # 从 dev-registry.json 获取邮箱
          EMAIL=$(cat data/dev-registry.json 2>/dev/null | \
            python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('$DEV_ID',{}).get('email',''))" 2>/dev/null || echo '')
          echo "email=$EMAIL" >> $GITHUB_OUTPUT
      
      - name: "✅ 校验 DEV 编号"
        run: |
          DEV_ID="$ steps.parse.outputs.dev_id "
          if [[ ! "$DEV_ID" =~ ^DEV-[0-9]{3}$ ]]; then
            echo "❌ 无效的 DEV 编号: $DEV_ID"
            exit 1
          fi

  # ===== Job 2: 部署到服务器沙盒 =====
  deploy-to-sandbox:
    needs: parse-and-validate
    runs-on: ubuntu-latest
    outputs:
      deploy_result: $ steps.deploy.outputs.result 
      deploy_detail: $ steps.deploy.outputs.detail 
    steps:
      - uses: actions/checkout@v4
      
      - name: "🔑 配置 SSH"
        run: |
          mkdir -p ~/.ssh
          echo "$ secrets.DEPLOY_KEY " > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan -H $ secrets.DEPLOY_HOST  >> ~/.ssh/known_hosts 2>/dev/null
      
      - name: "🏠 部署到沙盒"
        id: deploy
        env:
          DEV_ID: $ needs.parse-and-validate.outputs.dev_id 
          MODULE: $ needs.parse-and-validate.outputs.module 
          HOST: $ secrets.DEPLOY_HOST 
          USER: $ secrets.DEPLOY_USER 
        run: |
          SANDBOX="/var/www/${DEV_ID}/${MODULE}"
          echo "📦 部署目标: ${SANDBOX}"
          
          # 创建沙盒目录(如不存在)
          ssh ${USER}@${HOST} "mkdir -p ${SANDBOX}"
          
          # rsync 同步代码
          rsync -avz --delete \
            --exclude='.git' \
            --exclude='.dev-profile' \
            --exclude='node_modules' \
            ./ ${USER}@${HOST}:${SANDBOX}/
          
          # 设置权限(遵守部署适配协议 v1.0
          ssh ${USER}@${HOST} << 'REMOTE'
            chown -R nginx:nginx /var/www/${DEV_ID}/${MODULE}
            find /var/www/${DEV_ID}/${MODULE} -type d -exec chmod 755 {} \;
            find /var/www/${DEV_ID}/${MODULE} -type f -exec chmod 644 {} \;
          REMOTE
          
          echo "✅ 文件同步完成"
      
      - name: "🔍 运行 deploy-check.sh"
        id: check
        env:
          DEV_ID: $ needs.parse-and-validate.outputs.dev_id 
          MODULE: $ needs.parse-and-validate.outputs.module 
          HOST: $ secrets.DEPLOY_HOST 
          USER: $ secrets.DEPLOY_USER 
        run: |
          # 上传自检脚本
          scp scripts/deploy-check.sh ${USER}@${HOST}:/tmp/deploy-check.sh
          
          # 运行自检
          RESULT=$(ssh ${USER}@${HOST} "bash /tmp/deploy-check.sh ${DEV_ID} ${MODULE}" 2>&1) || true
          echo "$RESULT"
          
          if echo "$RESULT" | grep -q "FAIL"; then
            echo "result=failed" >> $GITHUB_OUTPUT
            echo "detail=$RESULT" >> $GITHUB_OUTPUT
          else
            echo "result=passed" >> $GITHUB_OUTPUT
            echo "detail=All checks passed" >> $GITHUB_OUTPUT
          fi
      
      - name: "🔥 运行 smoke-test.sh"
        id: smoke
        env:
          HOST: $ secrets.DEPLOY_HOST 
          USER: $ secrets.DEPLOY_USER 
        run: |
          scp scripts/smoke-test.sh ${USER}@${HOST}:/tmp/smoke-test.sh
          SMOKE=$(ssh ${USER}@${HOST} "bash /tmp/smoke-test.sh" 2>&1) || true
          echo "$SMOKE"
          
          if echo "$SMOKE" | grep -q "异常"; then
            echo "⚠️ 有模块冒烟检查失败,但不阻断当前部署"
          fi

  # ===== Job 3: 写结果 + 通知 =====
  notify-and-sync:
    needs: [parse-and-validate, deploy-to-sandbox]
    runs-on: ubuntu-latest
    if: always()
    steps:
      - uses: actions/checkout@v4
      
      - name: "📊 写入 deploy-status.json"
        run: |
          DEV_ID="$ needs.parse-and-validate.outputs.dev_id "
          MODULE="$ needs.parse-and-validate.outputs.module "
          RESULT="$ needs.deploy-to-sandbox.outputs.deploy_result "
          DETAIL="$ needs.deploy-to-sandbox.outputs.deploy_detail "
          TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
          
          # 读取现有状态文件或初始化
          STATUS_FILE="data/deploy-status.json"
          mkdir -p data
          [ -f "$STATUS_FILE" ] || echo '{}' > "$STATUS_FILE"
          
          # 更新状态
          python3 << EOF
import json
with open('$STATUS_FILE', 'r') as f:
    data = json.load(f)
data['${DEV_ID}/${MODULE}'] = {
    'dev_id': '${DEV_ID}',
    'module': '${MODULE}',
    'result': '${RESULT}',
    'detail': '${DETAIL}',
    'timestamp': '${TIMESTAMP}',
    'commit': '${GITHUB_SHA}'
}
with open('$STATUS_FILE', 'w') as f:
    json.dump(data, f, indent=2, ensure_ascii=False)
EOF
          
          git config user.name "zhuyuan-bot"
          git config user.email "zhuyuan@guanghulab.com"
          git add data/deploy-status.json
          git commit -m "🧠 deploy-status: ${DEV_ID}/${MODULE} → ${RESULT}" || true
          git push || true
      
      - name: "📧 发送部署结果邮件"
        if: needs.parse-and-validate.outputs.email != ''
        env:
          SMTP_USER: $ secrets.SMTP_USER 
          SMTP_PASS: $ secrets.SMTP_PASS 
          TO_EMAIL: $ needs.parse-and-validate.outputs.email 
          DEV_ID: $ needs.parse-and-validate.outputs.dev_id 
          MODULE: $ needs.parse-and-validate.outputs.module 
          RESULT: $ needs.deploy-to-sandbox.outputs.deploy_result 
        run: |
          if [ "$RESULT" = "passed" ]; then
            SUBJECT="✅ 部署成功:${DEV_ID}/${MODULE}"
            BODY="你的模块 ${MODULE} 已成功部署到 guanghulab.com\n\n访问地址https://guanghulab.com/${MODULE}/\n\n铸渊 · 光湖代码守护人格体"
          else
            SUBJECT="❌ 部署失败:${DEV_ID}/${MODULE}"
            BODY="你的模块 ${MODULE} 部署失败\n\n请检查你的模块是否符合『服务器部署适配协议 v1.0』\n\n错误详情请看仓库公告栏或 GitHub Actions 日志\n\n铸渊 · 光湖代码守护人格体"
          fi
          
          # 使用 Python smtplib 发送邮件QQ 邮箱 SMTP
          python3 << PYEOF
import smtplib
from email.mime.text import MIMEText
from email.header import Header

msg = MIMEText("""$BODY""", 'plain', 'utf-8')
msg['Subject'] = Header("$SUBJECT", 'utf-8')
msg['From'] = "$SMTP_USER"
msg['To'] = "$TO_EMAIL"

try:
    server = smtplib.SMTP_SSL('smtp.qq.com', 465)
    server.login("$SMTP_USER", "$SMTP_PASS")
    server.sendmail("$SMTP_USER", "$TO_EMAIL", msg.as_string())
    server.quit()
    print("✅ 邮件已发送到 $TO_EMAIL")
except Exception as e:
    print(f"⚠️ 邮件发送失败: {e}")
PYEOF
      
      - name: "📝 同步到 Notion 部署注册表"
        env:
          NOTION_TOKEN: $ secrets.NOTION_TOKEN 
          FINGERPRINT_DB_ID: $ secrets.FINGERPRINT_DB_ID 
          DEV_ID: $ needs.parse-and-validate.outputs.dev_id 
          MODULE: $ needs.parse-and-validate.outputs.module 
          RESULT: $ needs.deploy-to-sandbox.outputs.deploy_result 
        run: |
          node scripts/sync-deploy-to-notion.js || echo "⚠️ Notion 同步失败(不阻断主流程)"

五、开发者注册表(铸渊维护)

铸渊在仓库维护一份开发者注册表,用于自动部署时查找邮箱:

// data/dev-registry.json
{
  "DEV-001": {
    "name": "页页",
    "email": "",
    "modules": ["backend"],
    "sandbox": "/var/www/DEV-001/"
  },
  "DEV-002": {
    "name": "肥猫",
    "email": "",
    "modules": ["feishu-bot"],
    "sandbox": "/var/www/DEV-002/"
  },
  "DEV-005": {
    "name": "小草莓",
    "email": "",
    "modules": ["status-board", "cost-control", "persona-scheduler"],
    "sandbox": "/var/www/DEV-005/"
  },
  "DEV-010": {
    "name": "桔子",
    "email": "",
    "modules": ["channel-engine"],
    "sandbox": "/var/www/DEV-010/"
  }
}

邮箱由开发者第一次 push 时通过 pre-push hook 收集,或由人格体在 SYSLOG 中提取。

铸渊自动合并到注册表。


六、M22 公告栏对接

M22 主域公告栏自动读取 deploy-status.json,展示当前所有模块的部署状态:

// 公告栏前端代码片段
async function loadDeployStatus() {
  const res = await fetch('/data/deploy-status.json');
  const data = await res.json();
  
  const container = document.getElementById('deploy-board');
  container.innerHTML = '';
  
  for (const [key, info] of Object.entries(data)) {
    const card = document.createElement('div');
    card.className = `deploy-card ${info.result}`;
    card.innerHTML = `
      <div class="deploy-dev">${info.dev_id}</div>
      <div class="deploy-module">${info.module}</div>
      <div class="deploy-status">
        ${info.result === 'passed' ? '✅ 通过' : '❌ 失败'}
      </div>
      <div class="deploy-time">${info.timestamp}</div>
      ${info.result === 'failed' 
        ? `<button onclick="showDetail('${key}')"
             class="deploy-detail-btn">🔍 查看详情</button>` 
        : ''}
    `;
    container.appendChild(card);
  }
}

function showDetail(key) {
  // 打开详情模态框,展示报错信息
  // 人格体可以复制这些信息来引导开发者修复
}

七、定时同步到 Notion

铸渊每天两次04:00 + 14:00 UTC = 北京 12:00 + 22:00把部署状态同步到 Notion

# .github/workflows/sync-deploy-to-notion.yml
name: "📝 Sync Deploy Status to Notion"

on:
  schedule:
    - cron: '0 4,14 * * *'   # 北京 12:00 + 22:00
  workflow_dispatch:           # 手动触发

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: "🧠 唤醒铸渊核心大脑"
        run: |
          echo "🧠 铸渊核心大脑唤醒中..."
          echo "🔑 扫描 Secrets 权限..."
          # 检查必要密钥
          for KEY in NOTION_TOKEN FINGERPRINT_DB_ID SMTP_USER; do
            if [ -z "$(eval echo \$$KEY)" ]; then
              echo "⚠️ 缺失: $KEY"
            else
              echo "✅ 可用: $KEY"
            fi
          done
        env:
          NOTION_TOKEN: $ secrets.NOTION_TOKEN 
          FINGERPRINT_DB_ID: $ secrets.FINGERPRINT_DB_ID 
          SMTP_USER: $ secrets.SMTP_USER 
      
      - name: "📝 同步部署状态到 Notion"
        env:
          NOTION_TOKEN: $ secrets.NOTION_TOKEN 
          FINGERPRINT_DB_ID: $ secrets.FINGERPRINT_DB_ID 
        run: |
          node scripts/sync-deploy-to-notion.js
      
      - name: "🔥 远程冒烟检查"
        env:
          DEPLOY_HOST: $ secrets.DEPLOY_HOST 
          DEPLOY_USER: $ secrets.DEPLOY_USER 
          DEPLOY_KEY: $ secrets.DEPLOY_KEY 
        run: |
          mkdir -p ~/.ssh
          echo "$DEPLOY_KEY" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan -H $DEPLOY_HOST >> ~/.ssh/known_hosts 2>/dev/null
          scp scripts/smoke-test.sh ${DEPLOY_USER}@${DEPLOY_HOST}:/tmp/smoke-test.sh
          ssh ${DEPLOY_USER}@${DEPLOY_HOST} "bash /tmp/smoke-test.sh"

八、铸渊自行部署清单(读到就做)

铸渊自行部署清单(读到就做·不等人):

① 创建/更新 Workflow
   a. .github/workflows/sandbox-deploy.yml     ← 主部署流程
   b. .github/workflows/sync-deploy-to-notion.yml  ← 定时同步

② 创建脚本
   a. scripts/deploy-check.sh        ← 部署前自检(从部署适配协议复制)
   b. scripts/smoke-test.sh          ← 冒烟检查(从部署适配协议复制)
   c. scripts/sync-deploy-to-notion.js  ← Notion API 写入
   d. scripts/setup-sandbox.sh       ← 新开发者开户脚本

③ 创建数据文件
   a. data/deploy-status.json        ← 部署状态源(公告栏读取)
   b. data/dev-registry.json         ← 开发者注册表(邮箱+模块映射)

④ 服务器目录初始化(通过 SSH
   a. 创建 /var/www/_shared/ 目录
   b. 创建所有已注册 DEV 编号的沙盒目录
   c. 设置权限 nginx:nginx + 755
   d. 迁移现有模块到新沙盒结构:
      /var/www/hololake-frontend/status-board/ → /var/www/DEV-005/status-board/
      /var/www/hololake-frontend/cost-control/ → /var/www/DEV-005/cost-control/

⑤ 更新 Nginx 配置
   a. 添加所有 DEV 编号的 location 块
   b. 清理重复的 server 块(修复 conflicting server name 警告)
   c. nginx -t && systemctl reload nginx

⑥ M22 公告栏对接
   a. 在公告栏页面添加部署状态板块
   b. 读取 deploy-status.json 展示结果
   c. 失败时显示「🔍 查看详情」按钮

验收标准:
✅ 开发者 push 到 dev/DEV-XXX/模块名 分支 → 自动部署到服务器沙盒
✅ 部署后自动跑自检+冒烟检查
✅ 结果写入 deploy-status.json
✅ 公告栏可看到谁通过谁失败
✅ 失败时可点展详情看报错信息
✅ 开发者邮箱收到部署结果通知
✅ 每天两次自动同步到 Notion 模块指纹注册表

九、现有模块迁移计划

服务器现有模块需要从平铺结构迁移到沙盒结构:

现有路径 迁移到 开发者
/var/www/hololake-frontend/status-board/ /var/www/DEV-005/status-board/ DEV-005 小草莓
/var/www/hololake-frontend/cost-control/ /var/www/DEV-005/cost-control/ DEV-005 小草莓
/var/www/backend/ /var/www/backend/(保持,共享服务层) DEV-001 页页
/var/www/feishu-bot/ /var/www/feishu-bot/(保持,共享服务层) DEV-002 肥猫
/opt/guanghulab-dingtalk/ /var/www/dingtalk-bot/(保持,共享服务层) DEV-004 之之

十、协议版本

版本 日期 变更
v1.0 2026-03-15 首版 · 全套沙盒部署自动化闭环:身份注册+自动部署+自检+冒烟检查+公告栏+邮件通知+Notion同步