Commit 1715a81
authored
fix(scripts): count a codex approving reaction on the PR body as sign-off (#1568)
* fix(scripts): count a codex approving reaction on the PR body as sign-off
pre-merge-check.sh detected reviewer activity via reviews, PR comments,
SHA-pinned codex issue-comment verdicts, and reviewer check runs — but not
reactions. Codex (chatgpt-codex-connector[bot]) often signs off on a clean PR
by leaving a thumbs-up (+1) reaction on the PR description instead of posting a
review or comment, so such PRs blocked forever even though the required
reviewer had approved (observed on #1565).
Add PR-body reaction detection: a required reviewer counts as having weighed in
if they left an explicitly POSITIVE reaction (+1/heart/hooray/rocket) on the PR
body. Negative/ambiguous reactions (-1, confused, eyes) never count, and a
positive reaction from a non-reviewer is not credited to the reviewer. The
reactions read is non-fatal — a failure falls back to the other detection paths
rather than crashing the gate.
Extend tests/pre-merge-check.test.mjs: codex +1 signs off; negative reactions
and other users' reactions still block; a reactions-endpoint failure degrades
to a missing-reviewer verdict rather than an API-read crash.
* fix(scripts): bind reaction sign-off to the current head commit
Codex (P1 on #1568): a PR-body reaction carries no commit SHA and GitHub does
not dismiss it on new pushes, so a +1 left on an earlier revision would keep
satisfying the required reviewer for a newer diff it never saw — bypassing the
current-head protection the issue-comment verdict path enforces via SHA pinning.
Reactions can't be SHA-pinned, so bind by time: only count a reaction created
at/after the head commit's committer date. A commit pushed after the +1 has a
newer committer date and invalidates the stale reaction; a rebase rewrites
committer dates and does the same — both fail closed and force a fresh sign-off.
If the head commit date can't be read, no reaction counts. Timestamp compare is
byte-wise under LC_ALL=C on GitHub's fixed-format ISO-8601 UTC values.
Residual (documented): cherry-picking a commit with an OLD committer date as the
new head could re-admit a reaction in that window; the SHA-pinned issue-comment
path stays the strong signal.
Tests: reject a reaction predating the head commit; fail closed when the head
commit date is unknown.
* fix(scripts): bind reaction sign-off to head push time, not committer date
Codex (2nd P1 on #1568): committer date is not push-visibility time. A commit
amended/created locally at 10:00, a +1 left at 10:05 on the still-old head, then
the commit pushed at 10:10 — the reaction is not before the committer date
(10:00) so the previous fix still credited a reaction placed before the new SHA
was ever visible for review.
Bind instead to when the head became visible on the PR: HEAD_VISIBLE_AT =
earliest check-suite created_at for the head SHA (a push-time signal, stable
across job re-runs, and — unlike author/committer date — not backdatable by a
local amend or cherry-pick). A reaction counts only if created at/after that.
GitHub's Commit.pushedDate was the obvious field but is null in practice, so the
check-suite creation time is the reliable push marker. If it can't be read (no
suite yet / API failure), no reaction is credited — fail closed.
Tests updated: stale reaction now means "placed before the head's check-suite
(push) time"; the fail-closed scenario keys off missing push time.
* docs(scripts): document the accepted reaction-freshness residual
Repo-owner decision on codex's 3rd P1: check-suite created_at is keyed to the
SHA, not to when it became this PR's head, and GitHub exposes no clean per-PR
"head advanced at" timestamp (Commit.pushedDate is null in practice). The
remaining bypass needs the identical SHA pushed to two branches with an
adversarially-timed +1 — impossible in this repo's one-branch-per-PR flow. The
SHA-pinned issue-comment verdict stays the strong signal; reactions are a
convenience sign-off, not the security boundary. Document the residual explicitly
rather than drop reaction support (no reliable PR-scoped push signal exists).1 parent 35b6f38 commit 1715a81
2 files changed
Lines changed: 188 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | | - | |
13 | | - | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
14 | 18 | | |
15 | 19 | | |
16 | 20 | | |
| |||
127 | 131 | | |
128 | 132 | | |
129 | 133 | | |
| 134 | + | |
130 | 135 | | |
131 | 136 | | |
132 | 137 | | |
133 | 138 | | |
134 | 139 | | |
135 | 140 | | |
136 | 141 | | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
137 | 208 | | |
138 | 209 | | |
139 | 210 | | |
| |||
188 | 259 | | |
189 | 260 | | |
190 | 261 | | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
191 | 270 | | |
192 | 271 | | |
193 | 272 | | |
194 | 273 | | |
195 | | - | |
| 274 | + | |
| 275 | + | |
196 | 276 | | |
197 | 277 | | |
198 | 278 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
45 | | - | |
| 45 | + | |
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
| |||
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
71 | | - | |
| 71 | + | |
72 | 72 | | |
73 | 73 | | |
74 | 74 | | |
| |||
119 | 119 | | |
120 | 120 | | |
121 | 121 | | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
122 | 158 | | |
123 | 159 | | |
124 | 160 | | |
| |||
348 | 384 | | |
349 | 385 | | |
350 | 386 | | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
0 commit comments