Commit b8c21fc
authored
fix: use webhook payload SHAs in list_changed_files to avoid race condition (#1107)
<h3>PR Summary by Qodo</h3>
Fix changed-files diff race by using webhook payload base/head SHAs
<code>🐞 Bug fix</code> <code>🧪 Tests</code> <code>🕐 20-40 Minutes</code>
<img
src="https://www.qodo.ai/wp-content/uploads/2025/11/light-grey-line.svg"
height="10%" alt="Grey Divider">
<h3>Walkthroughs</h3>
<details open>
<summary>User Description</summary>
<br/>
## Summary
Replace live PyGithub API calls with webhook payload SHAs in
`list_changed_files()` to eliminate a race condition where base branch
receives new commits between clone and API call.
- Prefer webhook payload SHAs for `pull_request` events (no race
condition)
- Fall back to PullRequest API object for non-PR events (issue_comment,
check_run, etc.)
- Store `pr_base_sha`/`pr_head_sha` on GithubWebhook instance during
`process()`
- Remove `pull_request` parameter from `initialize()` and
`list_changed_files()`
- Add symmetric guards for both base and head SHA validation
Closes #1096
</details>
<details open>
<summary>AI Description</summary>
<br/>
<pre>
• Persist PR base/head SHAs from webhook payload to prevent base-branch
race conditions.
• Fall back to PullRequest API SHAs for non-PR webhook event types.
• Simplify OWNERS handler initialization by removing PullRequest
parameter plumbing.
</pre>
</details>
<details>
<summary>Diagram</summary>
<br/>
```mermaid
graph TD
A["GitHub webhook payload"] --> B["GithubWebhook.process"] --> C["Store PR base/head SHAs"] --> D[("Local clone")] --> E["OwnersFileHandler.list_changed_files"] --> F["git diff --name-only"]
B --> G["PullRequest API (fallback)"] --> C
```
</details>
<details>
<summary>High-Level Assessment</summary>
<br/>
Using webhook payload SHAs for pull_request events is the most reliable
way to keep the local clone and diff base/head aligned and eliminate the
observed race. Alternatives like always querying live PR/base refs or
diffing against the current base branch would reintroduce timing drift;
passing SHAs through additional parameters instead of storing on the
per-request GithubWebhook instance would add plumbing without changing
the core correctness.
</details>
<img
src="https://www.qodo.ai/wp-content/uploads/2025/11/light-grey-line.svg"
height="10%" alt="Grey Divider">
<h3>File Changes</h3>
<details>
<summary><strong>Bug fix</strong> (2)</summary>
<blockquote>
<details>
<summary><strong>github_api.py</strong> <code>Persist PR base/head SHAs
from payload with API fallback</code> <code>+21/-5</code></summary>
<br/>
>Persist PR base/head SHAs from payload with API fallback
>
><pre>
>• Stores pr_base_sha/pr_head_sha on the GithubWebhook instance during
process(), preferring pull_request payload SHAs to avoid timing drift.
Falls back to PullRequest base.sha/head.sha for non-pull_request event
payloads and updates OwnersFileHandler initialization calls to the new
signature.
></pre>
>
><a
href='https://github.com/myk-org/github-webhook-server/pull/1107/files#diff-7c5f6dfcadb38e75c2d0f1d418ba1a861cc9f6c0efe72905a250e9f43a6cfdcf'>webhook_server/libs/github_api.py</a>
<hr/>
</details>
</blockquote>
<blockquote>
<details>
<summary><strong>owners_files_handler.py</strong> <code>Read diff SHAs
from GithubWebhook; remove PullRequest parameter</code>
<code>+10/-11</code></summary>
<br/>
>Read diff SHAs from GithubWebhook; remove PullRequest parameter
>
><pre>
>• Removes the PullRequest parameter from initialize() and
list_changed_files(). list_changed_files() now reads base/head SHAs from
github_webhook.pr_base_sha/pr_head_sha and documents the race-condition
rationale.
></pre>
>
><a
href='https://github.com/myk-org/github-webhook-server/pull/1107/files#diff-1f6f88363e42edc5aeaab6ac0422002e56c81ae51f8f3f83c1cd3610813b8c3b'>webhook_server/libs/handlers/owners_files_handler.py</a>
<hr/>
</details>
</blockquote>
</details>
<details>
<summary><strong>Tests</strong> (2)</summary>
<blockquote>
<details>
<summary><strong>test_github_api.py</strong> <code>Add tests for SHA
storage from payload and API fallback</code>
<code>+107/-0</code></summary>
<br/>
>Add tests for SHA storage from payload and API fallback
>
><pre>
>• Introduces coverage verifying payload SHAs are preferred for
pull_request events and that non-PR events fall back to PullRequest API
SHAs. Mocks cloning/handler initialization to focus assertions on SHA
persistence behavior.
></pre>
>
><a
href='https://github.com/myk-org/github-webhook-server/pull/1107/files#diff-77f140ed13dff3ea105ea6374a5716a034664a753eafed149f305baf862006f4'>webhook_server/tests/test_github_api.py</a>
<hr/>
</details>
</blockquote>
<blockquote>
<details>
<summary><strong>test_owners_files_handler.py</strong> <code>Update
tests for new handler signatures and SHA source</code>
<code>+8/-10</code></summary>
<br/>
>Update tests for new handler signatures and SHA source
>
><pre>
>• Updates initialize() and list_changed_files() tests to match the
removed PullRequest parameter. Adjusts list_changed_files test setup to
provide SHAs via the mocked GithubWebhook instance.
></pre>
>
><a
href='https://github.com/myk-org/github-webhook-server/pull/1107/files#diff-a5967fb188d386a8c95bfa003af701b6d3c0ed7f85fd2a5ea9e16d4483032898'>webhook_server/tests/test_owners_files_handler.py</a>
<hr/>
</details>
</blockquote>
</details>
<img
src="https://www.qodo.ai/wp-content/uploads/2025/11/light-grey-line.svg"
height="10%" alt="Grey Divider">
<a href="https://www.qodo.ai"><img
src="https://www.qodo.ai/wp-content/uploads/2025/03/qodo-logo.svg"
width="80" alt="Qodo Logo"></a>1 parent d5390cc commit b8c21fc
4 files changed
Lines changed: 186 additions & 27 deletions
File tree
- webhook_server
- libs
- handlers
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
| 59 | + | |
| 60 | + | |
59 | 61 | | |
60 | 62 | | |
61 | 63 | | |
| |||
115 | 117 | | |
116 | 118 | | |
117 | 119 | | |
| 120 | + | |
| 121 | + | |
118 | 122 | | |
119 | 123 | | |
120 | 124 | | |
| |||
386 | 390 | | |
387 | 391 | | |
388 | 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 | + | |
389 | 430 | | |
390 | 431 | | |
391 | 432 | | |
| |||
449 | 490 | | |
450 | 491 | | |
451 | 492 | | |
452 | | - | |
| 493 | + | |
453 | 494 | | |
454 | 495 | | |
455 | 496 | | |
| |||
596 | 637 | | |
597 | 638 | | |
598 | 639 | | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
599 | 652 | | |
600 | 653 | | |
601 | 654 | | |
| |||
604 | 657 | | |
605 | 658 | | |
606 | 659 | | |
607 | | - | |
| 660 | + | |
608 | 661 | | |
609 | 662 | | |
610 | 663 | | |
| |||
618 | 671 | | |
619 | 672 | | |
620 | 673 | | |
621 | | - | |
| 674 | + | |
622 | 675 | | |
623 | 676 | | |
624 | 677 | | |
| |||
632 | 685 | | |
633 | 686 | | |
634 | 687 | | |
635 | | - | |
| 688 | + | |
636 | 689 | | |
637 | 690 | | |
638 | 691 | | |
| |||
678 | 731 | | |
679 | 732 | | |
680 | 733 | | |
681 | | - | |
| 734 | + | |
682 | 735 | | |
683 | 736 | | |
684 | 737 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
31 | | - | |
| 31 | + | |
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
40 | | - | |
| 40 | + | |
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| |||
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
87 | | - | |
| 87 | + | |
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
91 | 91 | | |
92 | | - | |
93 | | - | |
94 | | - | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
95 | 96 | | |
96 | 97 | | |
97 | 98 | | |
| |||
100 | 101 | | |
101 | 102 | | |
102 | 103 | | |
103 | | - | |
104 | | - | |
105 | | - | |
106 | | - | |
107 | | - | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
108 | 109 | | |
109 | 110 | | |
110 | 111 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
42 | | - | |
| 42 | + | |
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
| |||
419 | 419 | | |
420 | 420 | | |
421 | 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 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
422 | 529 | | |
423 | 530 | | |
424 | 531 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
38 | | - | |
| 38 | + | |
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
63 | | - | |
| 63 | + | |
64 | 64 | | |
65 | 65 | | |
66 | 66 | | |
| |||
87 | 87 | | |
88 | 88 | | |
89 | 89 | | |
90 | | - | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
97 | 95 | | |
98 | 96 | | |
99 | 97 | | |
| |||
105 | 103 | | |
106 | 104 | | |
107 | 105 | | |
108 | | - | |
| 106 | + | |
109 | 107 | | |
110 | 108 | | |
111 | 109 | | |
| |||
0 commit comments