-
Notifications
You must be signed in to change notification settings - Fork 0
fix(ci): simplify automated review evidence gate #4041
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a52d7f5
e857218
b07afba
7358310
6ac5efc
23f8be0
7962ab7
8bcb8ff
9567a97
895bd83
1c9acff
722d9af
44f7294
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,11 +2,12 @@ name: Automated review gate | |
|
|
||
| on: | ||
| pull_request_target: | ||
| types: [opened, synchronize, reopened, ready_for_review] | ||
| types: [opened, synchronize, reopened, ready_for_review, converted_to_draft] | ||
| pull_request_review: | ||
| types: [submitted, dismissed] | ||
| issue_comment: | ||
| types: [created, edited] | ||
| types: [created, edited, deleted] | ||
| status: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
@@ -20,13 +21,6 @@ permissions: | |
| pull-requests: write | ||
| statuses: write | ||
|
|
||
| concurrency: | ||
| group: automated-review-${{ github.event.pull_request.number || github.event.issue.number }} | ||
| # This workflow reconciles one mutable commit status. Canceling an older run | ||
| # leaves a canceled Actions check on the pull request SHA even when a later | ||
| # run publishes a successful status, so process every event in order. | ||
| queue: max | ||
|
|
||
| jobs: | ||
| review: | ||
| name: publish automated review status | ||
|
|
@@ -35,9 +29,13 @@ jobs: | |
| # write a commit status, so skip it there and let the trusted | ||
| # pull_request_target and issue_comment runs publish the decision instead. | ||
| if: >- | ||
| github.event_name != 'status' && | ||
| (github.event_name != 'issue_comment' || github.event.issue.pull_request) && | ||
| (github.event_name != 'pull_request_review' || | ||
| github.event.pull_request.head.repo.full_name == github.repository) | ||
| concurrency: | ||
| group: automated-review-status-publishers | ||
| queue: max | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 5 | ||
| steps: | ||
|
|
@@ -60,15 +58,16 @@ jobs: | |
| const gateUrl = pathToFileURL( | ||
| `${process.env.GITHUB_WORKSPACE}/scripts/ci/automated-review-gate.mjs`, | ||
| ).href; | ||
| let pullRequest = context.payload.pull_request; | ||
| if (!pullRequest) { | ||
| const response = await github.rest.pulls.get({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| pull_number: context.payload.issue.number, | ||
| }); | ||
| pullRequest = response.data; | ||
| } | ||
| const pullNumber = context.payload.pull_request?.number ?? | ||
| context.payload.issue.number; | ||
| const response = await github.rest.pulls.get({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| pull_number: pullNumber, | ||
| }); | ||
| const pullRequest = response.data; | ||
| const sameRepository = | ||
| `${context.repo.owner}/${context.repo.repo}`; | ||
| const headSha = pullRequest.head.sha; | ||
| let publishAutomatedReviewStatus; | ||
| try { | ||
|
|
@@ -98,6 +97,12 @@ jobs: | |
| headSha, | ||
| pullUrl: pullRequest.html_url, | ||
| isDraft: pullRequest.draft === true, | ||
| // Fork review events cannot publish a status. Ignore review | ||
| // objects for forks and accept only proof a trusted pull or | ||
| // comment event can reconcile. This safely stays pending until | ||
| // a trusted event observes status or comment proof. | ||
| allowPullRequestReviews: | ||
| pullRequest.head.repo?.full_name === sameRepository, | ||
| }); | ||
| if (result.state === "pending") { | ||
| core.notice(`${result.description}.`); | ||
|
|
@@ -145,3 +150,66 @@ jobs: | |
| ? "Skipped an automated review request from a stale synchronize event." | ||
| : "An automated review request for this head commit already exists.", | ||
| ); | ||
|
|
||
| status_review: | ||
| name: publish completed CodeRabbit review status | ||
| # This SHA-scoped path publishes only durable completion success. It shares | ||
| # the status publisher queue so it cannot race general PR reconciliation. | ||
| # The status payload carries no creator field, so pin the sender instead: | ||
| # for a bot-created commit status the sender is the bot itself. The gate | ||
| # helper then re-verifies the creator over the REST status history, where | ||
| # creator does exist, before treating the wakeup as completion proof. | ||
| if: >- | ||
| github.event_name == 'status' && | ||
| github.event.context == 'CodeRabbit' && | ||
| github.event.state == 'success' && | ||
| github.event.description == 'Review completed' && | ||
| github.event.sender.login == 'coderabbitai[bot]' && | ||
| github.event.sender.id == 136622811 && | ||
| github.event.sender.type == 'Bot' | ||
| concurrency: | ||
| group: automated-review-status-publishers | ||
| queue: max | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 5 | ||
| steps: | ||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| ref: ${{ github.event.repository.default_branch }} | ||
| persist-credentials: false | ||
| - name: Publish authenticated CodeRabbit completion | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| with: | ||
| retries: 3 | ||
| script: | | ||
| const { pathToFileURL } = require("node:url"); | ||
| const gateUrl = pathToFileURL( | ||
| `${process.env.GITHUB_WORKSPACE}/scripts/ci/automated-review-gate.mjs`, | ||
| ).href; | ||
| let publishCodeRabbitCompletionStatus; | ||
| try { | ||
| ({ publishCodeRabbitCompletionStatus } = await import(gateUrl)); | ||
| } catch (error) { | ||
| core.setFailed(`Could not load the review gate: ${error}`); | ||
| return; | ||
| } | ||
| const result = await publishCodeRabbitCompletionStatus({ | ||
| github, | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| headSha: context.payload.sha, | ||
| // The payload claim carries no creator; the helper authenticates | ||
| // the completion against the REST status history for the head. | ||
| status: { | ||
| context: context.payload.context, | ||
| state: context.payload.state, | ||
| description: context.payload.description, | ||
| }, | ||
| }); | ||
| if (result.state === "success") { | ||
| core.notice( | ||
| `Authenticated CodeRabbit completion for ${context.payload.sha.slice(0, 12)}.`, | ||
| ); | ||
| } else if (result.failure) { | ||
| core.warning(result.failure.message); | ||
|
Comment on lines
+213
to
+214
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When the associated-PR lookup, PR refetch, or commit-status publication exhausts its retries, Useful? React with 👍 / 👎. |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a fork PR where Codex submits a
COMMENTEDorAPPROVEDfindings review and CodeRabbit does not emit a completion status, thepull_request_reviewjob is skipped above and this passesfalse, causingfindAutomatedReviewto discard the only exact-head proof. No trusted comment or status event is guaranteed after that review, so theAutomated reviewstatus remains pending indefinitely and blocks the contribution; add a trusted wake-up path that can reconcile the pinned review or otherwise preserve that evidence for forks.Useful? React with 👍 / 👎.