name: PR Eval Dispatch # `/eval [sha=] [cases=]` PR 评论 → 触发内网评测流水线,报告由内网 bot 回贴。 # 本 workflow 只在默认分支上下文运行,不 checkout、不执行 PR 代码。 # 审核 SHA 规则:评测他人 PR 必须显式携带 sha=(审阅背书凭据,验证 # 其恰为当前 open head);评测自己创建的 PR 可省略,自动钉住派发时刻 # 的当前 head(作者自背书,无第三方偷换窗口);内网 CI 另以 # FETCH_HEAD 校验兜底派发后的变更。 # 授权两级:仓库 write/maintain/admin 可派发任意 PR;默认分支 # .github/eval-allowlist.txt 名单内的用户仅可派发自己创建的 PR。 # 触发通道:workflow 校验通过后发结构化评论(HTML 注释内嵌 JSON), # 内网 Devix 轮询服务每 3 分钟扫描 → 触发 Aone CI 流水线。 # 不再直接 curl 内网(公网 runner 结构性不可达)。 on: issue_comment: types: - created permissions: {} concurrency: group: eval-dispatch-${{ github.event.issue.number }} cancel-in-progress: false jobs: dispatch: name: Dispatch internal evaluation if: >- github.event.issue.pull_request && startsWith(github.event.comment.body, '/eval') runs-on: ubuntu-latest timeout-minutes: 5 permissions: contents: read issues: write pull-requests: read steps: - name: Check out default branch tooling uses: actions/checkout@v4 - name: Verify commenter dispatch authorization env: GH_TOKEN: ${{ github.token }} COMMENTER: ${{ github.event.comment.user.login }} PR_AUTHOR: ${{ github.event.issue.user.login }} EVAL_ALLOWLIST_PATH: .github/eval-allowlist.txt run: | # 不用 --fail:非协作者查权限返回 404 错误体,交由 guard 走名单分支;硬网络错误降级为空对象同样 fail-closed permission_json="$(curl --silent --show-error \ -H "Authorization: Bearer ${GH_TOKEN}" \ -H "Accept: application/vnd.github+json" \ "https://api.github.com/repos/${GITHUB_REPOSITORY}/collaborators/${COMMENTER}/permission")" || permission_json='{}' printf '%s' "$permission_json" | python3 scripts/ci/eval_dispatch_guard.py permission - name: Parse /eval command id: parse continue-on-error: true env: COMMENT_BODY: ${{ github.event.comment.body }} run: python3 scripts/ci/eval_comment_parse.py - name: Reply usage on parse failure if: steps.parse.outcome == 'failure' env: GH_TOKEN: ${{ github.token }} PR_NUMBER: ${{ github.event.issue.number }} PARSE_ERROR: ${{ steps.parse.outputs.error }} run: | body="❌ /eval 命令解析失败:${PARSE_ERROR}" jq -n --arg body "$body" '{body: $body}' | curl --fail --silent --show-error \ -X POST \ -H "Authorization: Bearer ${GH_TOKEN}" \ -H "Accept: application/vnd.github+json" \ --data @- \ "https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" > /dev/null exit 1 - name: Verify reviewed PR head id: pr env: GH_TOKEN: ${{ github.token }} PR_NUMBER: ${{ github.event.issue.number }} EXPECTED_PR_NUMBER: ${{ github.event.issue.number }} REVIEWED_SHA: ${{ steps.parse.outputs.reviewed_sha }} COMMENTER: ${{ github.event.comment.user.login }} run: | pr_json="$(curl --fail --silent --show-error \ -H "Authorization: Bearer ${GH_TOKEN}" \ -H "Accept: application/vnd.github+json" \ "https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}")" printf '%s' "$pr_json" \ | python3 scripts/ci/eval_dispatch_guard.py head \ >> "$GITHUB_OUTPUT" - name: Post dispatch marker and acknowledge env: GH_TOKEN: ${{ github.token }} PR_NUMBER: ${{ github.event.issue.number }} PR_HEAD_SHA: ${{ steps.pr.outputs.head_sha }} PRODUCTS: ${{ steps.parse.outputs.products }} CASES_REF: ${{ steps.parse.outputs.cases_ref }} RUN_ID: ${{ github.run_id }} run: | cases_note="" if [ -n "$CASES_REF" ]; then cases_note=",用例版本 \`${CASES_REF}\`" fi # 安全模型:结构化标记供内网轮询服务提取并触发 Aone CI。 # 防伪造保证由消费端三重校验(见 scripts/ci/eval_poll_validate.py): # 1. comment.user.login == 'github-actions[bot]'(平台级身份,不可冒充) # 2. comment.performed_via_github_app.slug == 'github-actions'(App 签名) # 3. payload.run_id 对应真实成功的 workflow run(GET /actions/runs/{id}) # 任意一层不通过即丢弃,普通用户手写评论无法通过上述校验。 dispatch_payload=$(jq -nc \ --arg pr "$PR_NUMBER" \ --arg sha "$PR_HEAD_SHA" \ --arg products "$PRODUCTS" \ --arg cases "$CASES_REF" \ --arg run_id "$RUN_ID" \ '{pr_number: $pr, pr_head_sha: $sha, products: $products, cases_ref: $cases, run_id: $run_id}') body=""$'\n'"🛰️ /eval 已受理:产品集 \`${PRODUCTS}\`${cases_note},评测对象 \`${PR_HEAD_SHA}\`。"$'\n'"内网评测流水线将在数分钟内由轮询服务触发,运行结束后由 bot 回贴报告(首行为基线对比头条)。" jq -n --arg body "$body" '{body: $body}' | curl --fail --silent --show-error \ -X POST \ -H "Authorization: Bearer ${GH_TOKEN}" \ -H "Accept: application/vnd.github+json" \ --data @- \ "https://api.github.com/repos/${GITHUB_REPOSITORY}/issues/${PR_NUMBER}/comments" > /dev/null