Repository navigation
fix(review-pr): 支持 pull_request_target 事件 - #293
Conversation
There was a problem hiding this comment.
结论
改动范围与声明目标不匹配:PR 标题与摘要声称「支持 pull_request_target 事件」,但快照实际只让 resolve_pr_event.resolve_event 接受该事件名。该事件并未接入任何工作流触发器,因此本次改动不会产生所宣称的行为。
证据
.github/workflows/review-pr.yml的on:仅有workflow_dispatch与issue_comment,preflight的if也只放行workflow_dispatch/issue_comment(并显式排除了pull_request)。没有任何工作流会以pull_request_target触发resolve_event,新增分支在现有仓库中不可达。.github/aicodingflow-tests/test_review_workflow_dispatch.py的test_review_workflow_uses_manual_and_comment_triggers_only明确断言pull_request_target不得出现在 review 工作流触发器中,看起来是有意的设计边界(该事件运行在具备写权限的默认分支上下文中)。- 新增测试只直接调用
resolver.resolve_event(...)/review_state(...),只验证脚本层行为,未覆盖端到端触发路径,无法证明pull_request_target真正被支持。
影响
改动本身无害(不影响 pull_request / issue_comment,也未新增触发器),但一旦后续 PR 真的接通 pull_request_target,review-pr.yml 中「Mark PR review status pending/complete」步骤的 github.event_name != 'pull_request' 条件会在缺少 head_repo == github.repository 防护时对该事件成立;对 fork PR 使用 pull_request_target 会让基于 head_repo 的校验变得关键而不透明,需同步澄清与加固。
建议
- 修正标题/摘要以反映实际范围(仅运行时事件解析与 review 状态校验),或补齐触发器、工作流门控及其测试,使改动与声明一致。
- 若确有意启用
pull_request_target,请同步更新test_review_workflow_uses_manual_and_comment_triggers_only的断言,并在工作流中显式加上head_repo == github.repository等限制,避免 fork PR 在具备写权限的上下文中被自动评审。
There was a problem hiding this comment.
整体判断:触发器、preflight 门控、resolve_pr_event.resolve_event 解析与新增测试改动彼此一致,先前的 open thread(resolve_pr_event.py:77 分支在仓库内不可达)在本 PR 补齐触发器和门控后已经不再成立,无需重复提出。
但本 PR 把一个已验证的产品行为事实改掉了却没有同步文档与安全说明,因此不建议直接合并:
pull_request_target会评审来自 fork 的 PR,与docs/product/raw/pr-review-verdict.md、docs/product/wiki/concepts/ai-pr-review-workflow.md、docs/product/wiki/summaries/pr-review-verdict.md中「来自 fork 的 PR 会被跳过、不运行 agent、不发布 review、不上传 artifact」的声明矛盾。- 该触发器会在 base 仓库上下文中运行,并可用
secrets.CODEX_API_KEY与pull-requests: write的 token,而门控对 PR 来源没有任何限制。
请同步更新 raw 与 wiki 文档,或者为新的触发路径保留同仓库 head 门控;若确认要评审 fork PR,请在 PR 描述与文档中写明这是有意的信任边界变更及相应缓解措施。
There was a problem hiding this comment.
结论:变更方向正确,未发现阻塞级问题,建议合并。
已核对:
review-pr.yml新增pull_request_target触发器,preflight 增加同仓库门控(github.event.pull_request.head.repo.full_name == github.repository);resolve_pr_event.resolve_event接受该事件,review_state用is_same_repo在 resolver 层再次拒绝 fork PR,gate 与 resolver 两层口径一致;.github/skills、.agents/contracts仍从 base 分支受控 checkout 覆盖pr-worktree,信任边界未被放宽。docs/product/raw/pr-review-verdict.md与两个 wiki 页面同步了触发方式、fork PR 跳过以及「只有 open、非 draft、同仓库 head PR 才进入 review」的口径,raw 与 wiki 一致。- 本地复核:
python3 -m unittest discover -s .github/aicodingflow-tests511 项、-s .github/tests13 项全部通过,含新增的pull_request_target与 fork 用例。
未解决的既有讨论
- 该 PR 上仍有两条未关闭线程(
review-pr.yml,comment 4291375605、4291375609)。其中「fork PR 会进入带 secrets 的 pull_request_target 运行」与「文档口径不一致」两点已由本次的同仓库门控、resolver 双重判断和 raw/wiki 更新覆盖;但同一线程提到的另一项仍未处理:同仓库 PR 会先被pull_request_target评审,再被参考 CI 成功后的workflow_dispatch评审,两条路径共用ai-pr-review-<number>并发组且cancel-in-progress: true,可能出现重复 review 评论 / 重复 API 消耗,或相互取消导致AI PR Reviewcommit status 与最终结果不一致。建议在关闭该线程时明确是否保留 CI dispatch 入口,或同步更新说明。
其他(无精确改动行可挂载)
docs/github-collaboration-flow.md的触发规则表与 PR Review 段落仍只描述「CI 成功后 dispatch」,未提及pull_request_target生命周期触发;如果该文档仍是权威入口说明,建议一并同步。docs/product/wiki/log.md未记录本次 wiki 页面改动,两个页面的last_reviewed仍为 2026-06-09;如需保持编译日志可追溯,建议补记。
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
There was a problem hiding this comment.
结论
workflow gate 与 resolver 双重防线的方向正确,新增/更新的测试在本地通过(.github/aicodingflow-tests/test_review_workflow_dispatch.py 9 项、.github/aicodingflow-tests/test_resolve_pr_event.py 18 项),pull_request_target 的同仓库门控(.github/workflows/review-pr.yml:37)与 review_state 的判定一致。阻塞项见 inline:同仓库门控让 non-member PR 在所有入口都不可评审,而已发布的 non-member gate / reviewer 请求流程及其文档没有同步说明。
其他发现(无精确改动行,按契约放在 body)
- 测试覆盖缺口:
review_state的新测试只覆盖pull_request_target与默认分支,未覆盖.github/scripts/resolve_pr_event.py:117的workflow_dispatch也要求同仓库这一新行为。此前手动 dispatch 可以评审 fork PR,现在会被静默跳过(preflight 只打印 skip_reason),建议在.github/aicodingflow-tests/test_resolve_pr_event.py补一个workflow_dispatch + fork用例。 - 状态写入文档滞后:
pull_request_target触发同样会写AI PR Reviewcommit status(review job 的 pending / complete 步骤条件只排除github.event_name != 'pull_request',见.github/workflows/review-pr.yml:103与:256),但docs/product/raw/pr-review-verdict.md的「Comment 与手动触发的 PR 关联」与docs/product/wiki/concepts/comment-manual-review-status.md仍只列 comment 与workflow_dispatch两种触发,建议同步为三种触发。
与既有讨论的关系
review_discussion_context.json 中 4 条已解决评论(fork 门控缺失、raw/wiki 文档同步、raw 文档换行)按重复抑制未再提出。
…ring' into fix/pull-request-target-event-wiring # Conflicts: # docs/product/raw/pr-review-verdict.md
There was a problem hiding this comment.
结论
本 PR 为 review-pr.yml 增加 pull_request_target 生命周期触发器,并在 workflow gate 与 resolve_pr_event.review_state 两层把自动入口限制为同仓库 head,同时保留 workflow_dispatch / 有效 comment 显式评审 fork PR 的路径,并同步 raw 与 wiki 文档。改动与既有行为自洽:gate 条件(.github/workflows/review-pr.yml:37)与 resolver 的 is_same_repo_target(.github/scripts/resolve_pr_event.py:114、:121、:127)一致,issue_comment 与 workflow_dispatch 的 fork 评审入口没有被误伤,post_pr_review.py 的 non-member 流程仍可达。本地运行 .github/aicodingflow-tests 全量用例通过(含 test_resolve_pr_event.py、test_review_workflow_dispatch.py,本环境有 yaml),未发现阻塞级发现。
未附行的提示
- commit status 文档未同步:新增
pull_request_target后,Mark PR review status pending/complete的条件是github.event_name != 'pull_request'且head_repo == github.repository,因此自动入口的 review 也会写入AI PR Reviewcommit status;docs/product/raw/pr-review-verdict.md的「Comment 与手动触发的 PR 关联」与docs/product/wiki/concepts/comment-manual-review-status.md仍只描述 comment / manual 触发,建议在本 PR 内补一句。 - 未附
recommended_reviewers:.github/CODEOWNERS中相关路径的 owner 只有 PR 作者本人,作为人工 reviewer 无意义。
Security
新增门控已覆盖 pull_request_target,但同一 workflow 的 comment 入口仍是任意用户可触发的 fork head 评审路径(见按行评论)。该行为早于本 PR,且 specs/issue-77 明确把触发权限模型列为 non-goal,因此不作为本次合并的阻塞项,建议记入后续任务。
重复反馈
review_discussion_context.json 中已 resolved 的三条历史评论(resolve_event 可达性、pull_request_target 的 fork 门控、CI dispatch 与自动入口的 concurrency 冲突)未再重复:当前 diff 已补齐触发器、门控、文档与测试。
There was a problem hiding this comment.
结论
APPROVE,无阻塞级发现。
变更核查
- 触发器:
review-pr.yml新增pull_request_target(opened/reopened/synchronize/ready_for_review),preflight gate 追加github.event.pull_request.head.repo.full_name == github.repository,与ci.yml、plan-approved.yml既有的同仓库 head 门控写法一致。 - 运行时防线:
resolve_event接受pull_request_target,review_state对pull_request_target与issue_comment都要求同仓库 head;workflow_dispatch仍保留显式评审 fork/draft PR 的路径,因此 non-member/reviewer 请求相关流程没有变成不可达代码。 - 安全边界:自动
pull_request_target入口只放行同仓库 head,review job 的 PR head checkout 只使用同仓库 repo/sha,session 上的secrets.CODEX_API_KEY与pull-requests: write/statuses: write不会用于未受信任的 fork head 内容,gate 与 resolver 判断同源(同一 payload 的head.repo.full_name),未发现绕过路径。 - 文档:raw 与 wiki(concepts/summaries)同步了触发入口、reviewable 条件、fork 边界与 draft 语义,逐条与
resolve_pr_event.py、review-pr.yml的实际行为核对一致,raw 与编译后的 wiki 在本次 PR 内互相支持。
验证
PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s .github/aicodingflow-tests -p 'test_resolve_pr_event.py':21 项通过。... -p 'test_review_workflow*.py':9 项通过(本环境yaml可用,工作流触发器/门控断言已真实执行)。- 整套
.github/aicodingflow-tests与.github/tests均通过。
非阻塞说明
前轮讨论中「PR 事件自动触发与 CI dispatch 路径并存」这一点的背景仍成立:同仓库 PR 会先由 PR 事件触发一次 review,CI 成功后 workflow_dispatch 再触发一次,两者共享 ai-pr-review-<number> 并发组。该线索在前轮已被 resolve,且本次改动没有引入更高severity的新风险,因此不再作为 inline 意见重复。若要收口,可考虑让参考 CI 不再重复 dispatch,或把 docs/product/raw/pr-review-verdict.md:9-13(未改动上下文行)「默认由目标项目 CI 成功路径触发」的表述与新入口顺序对齐——编译后的 wiki 页面已改成「可由 pull_request_target 触发,也可由 CI dispatch 触发」。
摘要
review-pr.yml监听pull_request_target的 PR 生命周期事件,并仅放行同仓库 head PR。resolve_pr_event支持该事件,并在 resolver 层拒绝 fork PR,形成 workflow gate 与运行时双重防线。验证
PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s .github/aicodingflow-tests -p 'test_resolve_pr_event.py'(18 项通过)PYTHONPYCACHEPREFIX=/tmp/aicodingflow-pycache python3 -m py_compile .github/scripts/resolve_pr_event.py .github/aicodingflow-tests/test_resolve_pr_event.py .github/aicodingflow-tests/test_review_workflow_dispatch.pygit diff --check工作流测试未运行:当前环境缺少
yamlPython 模块。