# ═══════════════════════════════════════════════ # 🔺 Sovereign: TCS-0002∞ | Root: SYS-GLW-0001 # 📜 Copyright: 国作登字-2026-A-00037559 # ═══════════════════════════════════════════════ # # 天眼 · PR 合并风险检查 # SkyEye PR Merge Risk Check # # 弥补天眼系统在 PR 合并环节的安全缺口: # gate-guard v1/v2 保护 push 事件 # 本工作流保护 pull_request 事件(合并前风险评估) # # 风险检测维度: # R1 · 关键文件覆盖检测(docs/index.html 等) # R2 · 受保护路径入侵检测 # R3 · 构建产物误入检测 # R4 · 开发者路径权限检测 # R5 · 大规模删除检测 # name: 天眼 · PR风险检查 on: pull_request: branches: [main] types: [opened, synchronize, reopened] permissions: contents: read pull-requests: write jobs: risk-check: name: 🛡️ PR合并风险评估 runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Collect PR changed files env: GH_TOKEN: ${{ github.token }} run: | # Get the list of files changed in this PR gh pr diff ${{ github.event.pull_request.number }} --name-only > /tmp/pr_files.txt || true # Get diff stats gh pr diff ${{ github.event.pull_request.number }} --stat > /tmp/pr_stats_raw.txt || true # Parse stats into numstat-like format for the script # Extract additions/deletions from the stat output git diff --numstat origin/${{ github.base_ref }}...origin/${{ github.head_ref }} > /tmp/pr_stats.txt 2>/dev/null || true echo "📂 Changed files:" cat /tmp/pr_files.txt echo "" echo "📊 Stats:" cat /tmp/pr_stats.txt - name: 🔍 天眼 PR 风险检查 id: risk_check env: PR_AUTHOR: ${{ github.event.pull_request.user.login }} PR_FILES: /tmp/pr_files.txt PR_STATS: /tmp/pr_stats.txt run: node scripts/skyeye/pr-risk-check.js - name: 📝 Write risk report comment if: always() uses: actions/github-script@v7 with: script: | const fs = require('fs'); const decision = '${{ steps.risk_check.outcome }}'; const riskLevel = '${{ steps.risk_check.outputs.risk_level }}' || 'unknown'; const riskSummary = '${{ steps.risk_check.outputs.risk_summary }}' || ''; const author = '${{ github.event.pull_request.user.login }}'; let body = '## 🛡️ 天眼 · PR合并风险检查报告\n\n'; body += `**PR作者:** ${author}\n`; body += `**检查时间:** ${new Date().toISOString()}\n\n`; if (decision === 'success') { body += '### ✅ 风险检查通过\n\n'; body += `风险等级: **${riskLevel}**\n\n`; if (riskSummary && riskSummary !== '仓库主人 PR,直接放行' && riskSummary !== '白名单用户 PR,直接放行') { body += '> ⚠️ 注意事项:\n'; body += `> ${riskSummary}\n\n`; } body += '此 PR 可以安全合并。\n'; } else { body += '### ❌ 风险检查未通过\n\n'; body += `风险等级: **${riskLevel}**\n\n`; body += '**检测到的风险:**\n'; if (riskSummary) { const items = riskSummary.split(' | '); for (const item of items) { body += `- 🔴 ${item}\n`; } } body += '\n⛔ **此 PR 已被天眼系统阻止合并。**\n'; body += '请联系仓库管理员 (TCS-0002∞) 审核。\n'; } body += '\n---\n'; body += '> 天眼 · PR合并风险检查引擎 · SkyEye PR Risk Check'; await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body: body });