name: lighthouse-cn-rollback

# ════════════════════════════════════════════════════════════════
# 光湖灯塔 · 一键回滚 (手动触发)
# Sovereign: TCS-0002∞ · 国作登字-2026-A-00037559
# 守护: 铸渊 · ICE-GL-ZY001
#
# 用法: Actions → lighthouse-cn-rollback → Run workflow
#   server_target: main / backup
#   snapshot_ts:   留空 = 回到上一个快照; 填具体时间戳 = 回到那一份
#   confirm_phrase: 必须填『我确认回滚』, 否则只列快照不执行
#
# 与 lighthouse-cn-deploy 的 stage=rollback 等价, 但单独建一个 workflow
# 是给霜砚 / Awen 一个明显的"红按钮", 不会跟部署混在一起误触.
# ════════════════════════════════════════════════════════════════

on:
  workflow_dispatch:
    inputs:
      server_target:
        description: '回滚目标'
        required: true
        default: 'main'
        type: choice
        options:
          - main
          - backup
      snapshot_ts:
        description: '快照时间戳 (留空=上一个; 用 list-only 模式查可用快照)'
        required: false
        default: ''
        type: string
      mode:
        description: '操作模式'
        required: true
        default: 'list-only'
        type: choice
        options:
          - list-only
          - rollback
      confirm_phrase:
        description: 'rollback 模式必填 · 输入 "我确认回滚" 才会真跑'
        required: false
        default: ''
        type: string

permissions:
  contents: read

concurrency:
  group: lighthouse-cn-rollback-${{ inputs.server_target }}
  cancel-in-progress: false

jobs:
  preflight:
    name: 启动前预检
    runs-on: ubuntu-latest
    timeout-minutes: 5
    outputs:
      effective_mode: ${{ steps.gate.outputs.effective_mode }}
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with: { node-version: '20' }

      - name: 密钥预检
        env:
          ZY_LIGHTHOUSE_HOST: ${{ secrets.ZY_LIGHTHOUSE_HOST }}
          ZY_LIGHTHOUSE_USER: ${{ secrets.ZY_LIGHTHOUSE_USER }}
          ZY_LIGHTHOUSE_KEY: ${{ secrets.ZY_LIGHTHOUSE_KEY }}
          ZY_LIGHTHOUSE_PORT: ${{ secrets.ZY_LIGHTHOUSE_PORT }}
          ZY_LIGHTHOUSE_BACKUP_HOST: ${{ secrets.ZY_LIGHTHOUSE_BACKUP_HOST }}
          ZY_LIGHTHOUSE_BACKUP_USER: ${{ secrets.ZY_LIGHTHOUSE_BACKUP_USER }}
          ZY_LIGHTHOUSE_BACKUP_KEY: ${{ secrets.ZY_LIGHTHOUSE_BACKUP_KEY }}
        run: |
          node scripts/preflight/check-secrets.js \
            --workflow lighthouse-cn-deploy \
            --stage rollback \
            --target "${{ inputs.server_target }}"

      - name: 误触锁
        id: gate
        env:
          MODE: ${{ inputs.mode }}
          PHRASE: ${{ inputs.confirm_phrase }}
        run: |
          set -e
          EFFECTIVE="$MODE"
          if [ "$MODE" = "rollback" ] && [ "$PHRASE" != "我确认回滚" ]; then
            echo "═══════════════════════════════════════════════"
            echo "  ⚠️  误触保护: 选了 rollback 但 confirm_phrase != 『我确认回滚』"
            echo "       自动降级为 list-only 模式 (只列快照, 不真回滚)."
            echo "       要真跑回滚, 重新 Run workflow 并在 confirm_phrase"
            echo "       字段填入: 我确认回滚"
            echo "═══════════════════════════════════════════════"
            EFFECTIVE="list-only"
          fi
          echo "effective_mode=$EFFECTIVE" >> "$GITHUB_OUTPUT"

  rollback:
    name: ${{ inputs.server_target }} · ${{ needs.preflight.outputs.effective_mode }}
    needs: preflight
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v4

      - name: 装载 SSH 凭据
        id: target
        env:
          MAIN_HOST: ${{ secrets.ZY_LIGHTHOUSE_HOST }}
          MAIN_USER: ${{ secrets.ZY_LIGHTHOUSE_USER }}
          MAIN_KEY: ${{ secrets.ZY_LIGHTHOUSE_KEY }}
          MAIN_PORT: ${{ secrets.ZY_LIGHTHOUSE_PORT }}
          BACKUP_HOST: ${{ secrets.ZY_LIGHTHOUSE_BACKUP_HOST }}
          BACKUP_USER: ${{ secrets.ZY_LIGHTHOUSE_BACKUP_USER }}
          BACKUP_KEY: ${{ secrets.ZY_LIGHTHOUSE_BACKUP_KEY }}
          TARGET: ${{ inputs.server_target }}
        run: |
          set -euo pipefail
          if [ "$TARGET" = "main" ]; then
            HOST="$MAIN_HOST"; USER="$MAIN_USER"; KEY="$MAIN_KEY"; PORT="${MAIN_PORT:-22}"
          else
            HOST="$BACKUP_HOST"; USER="$BACKUP_USER"; KEY="$BACKUP_KEY"; PORT="22"
          fi
          if [ -z "$HOST" ] || [ -z "$KEY" ]; then
            echo "❌ 目标 ($TARGET) 凭据缺失" >&2; exit 1
          fi
          umask 077; mkdir -p ~/.ssh
          printf '%s\n' "$KEY" > ~/.ssh/lighthouse_key
          chmod 600 ~/.ssh/lighthouse_key
          ssh-keyscan -p "$PORT" -H "$HOST" >> ~/.ssh/known_hosts 2>/dev/null || true
          echo "host=$HOST" >> "$GITHUB_OUTPUT"
          echo "user=$USER" >> "$GITHUB_OUTPUT"
          echo "port=$PORT" >> "$GITHUB_OUTPUT"

      - name: 列出可用快照
        env:
          HOST: ${{ steps.target.outputs.host }}
          USER: ${{ steps.target.outputs.user }}
          PORT: ${{ steps.target.outputs.port }}
        run: |
          set -e
          ssh -i ~/.ssh/lighthouse_key -p "$PORT" \
              -o StrictHostKeyChecking=accept-new \
              "$USER@$HOST" \
              "bash /opt/guanghu/lighthouse-cn/rollback.sh --list" \
            2>&1 | tee snapshot-list.log

      - name: 校验 snapshot_ts 格式 (防注入)
        if: needs.preflight.outputs.effective_mode == 'rollback'
        env:
          TS: ${{ inputs.snapshot_ts }}
        run: |
          set -e
          # snapshot_ts 来自 workflow_dispatch 用户输入, 后面要进 ssh
          # 远程命令字符串. 必须严格白名单, 防止空格/分号/反引号等注入.
          # 合法形式 (来自 rollback.sh `date +%Y%m%d-%H%M%S`):
          #   YYYYMMDD-HHMMSS
          #   YYYYMMDD-HHMMSS-pre-rollback   (rollback.sh 自动派生)
          #   空                              (= 回到上一个快照)
          if [ -n "$TS" ] && ! printf '%s' "$TS" | grep -Eq '^[0-9]{8}-[0-9]{6}(-pre-rollback)?$'; then
            echo "❌ snapshot_ts 格式不合法: 「$TS」" >&2
            echo "   合法形式: YYYYMMDD-HHMMSS 或 YYYYMMDD-HHMMSS-pre-rollback" >&2
            echo "   或留空 (= 回滚到最近一次快照)" >&2
            exit 1
          fi
          echo "✅ snapshot_ts 格式校验通过${TS:+: $TS}"

      - name: 执行回滚
        if: needs.preflight.outputs.effective_mode == 'rollback'
        env:
          HOST: ${{ steps.target.outputs.host }}
          USER: ${{ steps.target.outputs.user }}
          PORT: ${{ steps.target.outputs.port }}
          TS: ${{ inputs.snapshot_ts }}
        run: |
          set -e
          # TS 已在上一步白名单校验, 这里仍走 argv 传入而非命令字符串拼接,
          # 以双层防护: 远程 sh 接到的是 $1 / $2, 不是字面拼好的字符串.
          if [ -n "$TS" ]; then
            # 远程 sh -c 'cmd "$1"' _ "$TS" 这种调法:
            #   - 引号内的 'bash ... --to "$1"' 是远程 shell 字面接收的命令
            #   - 后面 _ 作为远程 sh 的 $0 (占位, 习惯用 _ 表示"不关心")
            #   - "$TS" 作为远程 sh 的 $1, 由 ssh 安全地走 argv 传过去,
            #     不会被本地或远程 shell 二次解释 → 即使 TS 含特殊字符
            #     也不会被注入 (上一步已正则白名单, 这里是双层防御)
            ssh -i ~/.ssh/lighthouse_key -p "$PORT" \
                -o StrictHostKeyChecking=accept-new \
                "$USER@$HOST" \
                'bash /opt/guanghu/lighthouse-cn/rollback.sh --to "$1"' \
                _ "$TS" \
              2>&1 | tee rollback-output.log
          else
            ssh -i ~/.ssh/lighthouse_key -p "$PORT" \
                -o StrictHostKeyChecking=accept-new \
                "$USER@$HOST" \
                'bash /opt/guanghu/lighthouse-cn/rollback.sh' \
              2>&1 | tee rollback-output.log
          fi

      - name: 拉回回执
        if: always()
        env:
          HOST: ${{ steps.target.outputs.host }}
          USER: ${{ steps.target.outputs.user }}
          PORT: ${{ steps.target.outputs.port }}
        run: |
          set -uo pipefail
          mkdir -p artifacts
          scp -i ~/.ssh/lighthouse_key -P "$PORT" \
              -o StrictHostKeyChecking=accept-new \
              "$USER@$HOST:/opt/guanghu/_logs/rollback-*.json" \
              artifacts/ 2>/dev/null || echo "(no rollback receipt yet — 可能是 list-only 模式)"
          ls -la artifacts/ || true

      - name: 上传回执
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: lighthouse-rollback-${{ inputs.server_target }}-${{ github.run_id }}
          path: |
            artifacts/
            snapshot-list.log
            rollback-output.log
          retention-days: 30
          if-no-files-found: warn

      - name: 清理 SSH 私钥
        if: always()
        run: rm -f ~/.ssh/lighthouse_key
