Skip to content

fix: remove check_suite/push/label from webhook event routing#510

Open
aglichandrap wants to merge 3 commits into
ramimbo:mainfrom
aglichandrap:fix/webhook-event-handling-csv-env
Open

fix: remove check_suite/push/label from webhook event routing#510
aglichandrap wants to merge 3 commits into
ramimbo:mainfrom
aglichandrap:fix/webhook-event-handling-csv-env

Conversation

@aglichandrap
Copy link
Copy Markdown

@aglichandrap aglichandrap commented May 27, 2026

Summary

Fixes webhook event routing for check_suite, push, and label GitHub events.

Bug Description

Events check_suite, push, and label were being routed to _handle_accepted_issue_label(), which expects issues or pull_request payload structures. These event types have different payload schemas:

  • check_suite events have: action, check_suite, repository, sender
  • push events have: ref, repository, pusher, commits
  • label events are for label CRUD (create/edit/delete on a repo), NOT for labeling issues/PRs (those fire as issues events with action=labeled)

Since these payloads lack issue and pull_request top-level fields, the handler always returned missing_issue status, recording a misleading webhook event.

Fix

Removed check_suite, push, and label from the event type routing. Only issues and pull_request events are now routed to the label handler. Other event types are properly ignored.

# Before
if event_type in {"issues", "pull_request", "label", "check_suite", "push"}:

# After
if event_type in {"issues", "pull_request"}:

Testing

  • Verified that check_suite and push events are now recorded as ignored
  • Verified that issues and pull_request events still route correctly to the label handler
  • Existing tests should continue to pass since the removed event types were always returning missing_issue anyway

Summary by CodeRabbit

  • Bug Fixes
    • Refined GitHub webhook routing: only issues and pull request events are processed; label, check_suite, and push events are now recorded as ignored and return an ignored status.
  • Tests
    • Added regression tests confirming ignored events return ignored and issues/pull request events continue to route and update balances.

Review Change Stack

Events 'check_suite', 'push', and 'label' were being routed to
_handle_accepted_issue_label(), which expects 'issues' or
'pull_request' payload structures. These event types don't have
'issue' or 'pull_request' top-level fields, so the handler always
returned 'missing_issue' status.

- 'check_suite' events have: action, check_suite, repository, sender
- 'push' events have: ref, repository, pusher, commits
- 'label' events are for label CRUD (create/edit/delete), not for
  labeling issues/PRs (those fire as 'issues' events with action='labeled')

Fix: Only route 'issues' and 'pull_request' events to the label handler.
Other event types are now properly ignored.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

📝 Walkthrough

Walkthrough

The webhook router now forwards only issues and pull_request events to _handle_accepted_issue_label; label, check_suite, and push events are recorded as ignored. A new test module adds HMAC/header helpers and tests ignored vs handled routing and balance effects.

Changes

Webhook event-type routing

Layer / File(s) Summary
Event-type filtering for issue label handling
app/webhooks/github.py
The event-type check before calling _handle_accepted_issue_label is narrowed to accept only issues and pull_request events. Other GitHub event types (label, check_suite, push) now fall through to the ignored path.
Regression tests and webhook helpers
tests/test_webhook_event_routing.py
Adds SECRET, HMAC signature helper and header-wrapping helper plus tests that assert check_suite, push, and label events return {"status":"ignored"} and persist WebhookEvent.processed_status == "ignored", and that issues and pull_request events route to the label handler and return {"status":"paid"} with expected contributor balance updates.

Possibly related PRs:

  • ramimbo/mergework#515: Adjusts LINKED_ISSUE_RE and also affects how pull_request webhook payloads are parsed/persisted into paid outcomes.
🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concretely names the changed surface: removal of three event types from webhook routing.
Description check ✅ Passed The description covers the bug, fix, and testing, but lacks some template sections like bounce capacity check and full test evidence checklist.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Mergework Public Artifact Hygiene ✅ Passed PR modifies only webhook routing code and tests. No README, docs, or public artifact changes; no MRWK claims present.
Bounty Pr Focus ✅ Passed Diff matches stated scope: routing narrowed to {"issues", "pull_request"}, 5 regression tests added, no unrelated changes. Check not applicable—no Bounty#/Refs# reference found.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@jtc268
Copy link
Copy Markdown
Contributor

jtc268 commented May 27, 2026

This routing change looks directionally right, but I think this needs a focused regression test before merge.

The diff changes the signed webhook behavior for check_suite, push, and label from missing_issue to ignored, but tests/test_webhooks.py has no direct coverage for those event types. The existing webhook suite still passes because it does not exercise the new ignored-event branch.

What I checked:

  • inspected app/webhooks/github.py and tests/test_webhooks.py
  • confirmed the only code diff is narrowing the routed event set to issues and pull_request
  • ran PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run --extra dev python -m pytest tests/test_webhooks.py -q -> 18 passed
  • ran PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run --extra dev python -m pytest tests/test_security.py::test_signed_webhook_with_invalid_json_is_rejected tests/test_security.py::test_duplicate_webhook_delivery_with_different_payload_is_rejected tests/test_security.py::test_webhook_rejects_unapproved_accepted_labeler -q -> 3 passed
  • ran uv run --extra dev ruff check app/webhooks/github.py tests/test_webhooks.py and ruff format --check -> passed
  • ran uv run --extra dev python -m mypy app/webhooks/github.py -> success
  • locally called handle_github_webhook() with signed check_suite, push, and label payloads on this branch and got ignored recorded for each

Suggested fix: add a compact parameterized test that sends signed check_suite, push, and label payloads and asserts both the return status and stored WebhookEvent.processed_status are ignored. That would make the intended boundary permanent instead of relying on the one-line route change alone.

Copy link
Copy Markdown
Contributor

@Karry2019web Karry2019web left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review ✅ APPROVED

FILES INSPECTED: app/webhooks/github.py

BEHAVIOR CHECKED:

  • The removed event types (check_suite, push, label) are not issue/label events — they should fall through to _record_event and not be routed to _handle_accepted_issue_label.
  • The remaining set {"issues", "pull_request"} correctly matches only events that carry issue-context payloads.
  • No regression risk: these events were already handled as no-op passthroughs in earlier routing logic.

TESTS VERIFIED:

  • No existing test asserted specific behavior for these removed event types in the _handle_accepted_issue_label path — the fix is safe.

CI REVIEWED: Clean mergeable state, single-line change, no lint concerns.

Verify that check_suite and push events are recorded as 'ignored'
(not routed to the label handler), while issues and pull_request
events continue to route correctly.
@aglichandrap
Copy link
Copy Markdown
Author

Regression test added and pushed to fix/webhook-event-handling-csv-env.

tests/test_webhook_event_routing.py — 4 focused tests:

  1. check_suite events are recorded as "ignored" (not routed to label handler)
  2. push events are recorded as "ignored"
  3. issues events still route correctly → "paid"
  4. pull_request events still route correctly → "paid"

All existing webhook tests (18) continue to pass.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b4869dec-7fff-4016-8795-7890bc75c4c1

📥 Commits

Reviewing files that changed from the base of the PR and between 9f12bf5 and 50d1916.

📒 Files selected for processing (1)
  • tests/test_webhook_event_routing.py

Comment thread tests/test_webhook_event_routing.py
Copy link
Copy Markdown
Contributor

@Zejia Zejia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current head 50d1916060c9500c86734cfd8098ff1dff738667 still needs a small cleanup before merge.

The new regression tests cover the intended check_suite and push ignored paths, and the webhook behavior itself looks right. The blocker is that CI is red because tests/test_webhook_event_routing.py is not formatted/organized according to Ruff. GitHub's failed job reports Would reformat: tests/test_webhook_event_routing.py; locally I also get an I001 import-order failure on the same file.

I would run Ruff format/fix on the new test file before merging. I would also add the missing label ignored-event case while touching it, because the code removed label from the routed set too, but the new regression file only locks check_suite and push.

Checked locally:

  • pytest tests/test_webhook_event_routing.py tests/test_webhooks.py -q -> 22 passed
  • ruff format --check tests/test_webhook_event_routing.py -> fails, 1 file would be reformatted
  • ruff check app/webhooks/github.py tests/test_webhook_event_routing.py -> fails on import organization in the new test file
  • git diff --check origin/main...HEAD -> clean

Copy link
Copy Markdown

@eliasx45 eliasx45 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed current head 50d1916060c9500c86734cfd8098ff1dff738667 for PR #510.

I am requesting changes. The webhook routing behavior looks directionally correct and the new tests pass functionally, but the branch is still not merge-ready because the new test file fails Ruff formatting/import checks. The implementation also removes label from the routed event set, but the regression coverage only locks check_suite and push ignored behavior; it should include the label ignored-event case too.

Evidence checked:

  • app/webhooks/github.py: event routing is narrowed from {"issues", "pull_request", "label", "check_suite", "push"} to {"issues", "pull_request"}.
  • tests/test_webhook_event_routing.py: covers check_suite and push as ignored, and verifies issues/pull_request still pay; it does not cover label even though that event type also changed behavior.

Validation run locally:

  • .\\.venv\\Scripts\\python.exe -m pytest tests\\test_webhook_event_routing.py tests\\test_webhooks.py -q -> 22 passed
  • .\\.venv\\Scripts\\python.exe -m ruff format --check tests\\test_webhook_event_routing.py -> fails: Would reformat: tests\\test_webhook_event_routing.py
  • .\\.venv\\Scripts\\python.exe -m ruff check app\\webhooks\\github.py tests\\test_webhook_event_routing.py -> fails with I001 import block unsorted/unformatted in tests/test_webhook_event_routing.py
  • git diff --check origin/main...HEAD -> clean

Suggested fix: run Ruff format/fix on tests/test_webhook_event_routing.py, and add a compact label event test asserting the signed webhook returns {"status": "ignored"} and stores WebhookEvent.processed_status == "ignored".

No private data, credentials, wallet material, signatures beyond local test HMACs, production mutation, fund movement, MRWK price/off-ramp, exchange/liquidity claim, bridge claim, or fabricated payout claim was used.

- Add test_label_event_is_ignored to cover the 'label' event type
  regression path (previously unrouted, now recorded as 'ignored')
- Fix import sorting per ruff I001
- Fix whitespace/formatting per ruff format

Addresses review feedback from Zejia and eliasx45.
@aglichandrap
Copy link
Copy Markdown
Author

@Zejia @eliasx45 Thanks for the review! Both items addressed:

  1. Ruff formatting — ran ruff format + ruff check --fix, import sorting fixed (I001)
  2. Missing label event test — added test_label_event_is_ignored that verifies the label event type is recorded as "ignored" (not routed to label handler)

All 5 regression tests now pass:

  • test_check_suite_event_is_ignored
  • test_push_event_is_ignored
  • test_label_event_is_ignored ← NEW
  • test_issues_event_routes_to_label_handler
  • test_pull_request_event_routes_to_label_handler

Ready for re-review! 🙏

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 156fd294-525f-4d21-8e45-ebb73528f80d

📥 Commits

Reviewing files that changed from the base of the PR and between 50d1916 and e437a7f.

📒 Files selected for processing (1)
  • tests/test_webhook_event_routing.py

Comment on lines +79 to +97
def test_label_event_is_ignored(sqlite_url: str) -> None:
"""label events must NOT be routed to the label handler."""
create_schema(sqlite_url)
payload = {
"action": "created",
"label": {"name": "bug"},
"repository": {"full_name": "ramimbo/mergework"},
"sender": {"login": "maintainer"},
}
headers, body = _wrap("label", payload, "delivery-label")

result = handle_github_webhook(sqlite_url, headers, body, SECRET)

assert result == {"status": "ignored"}
with session_scope(sqlite_url) as session:
event = session.get(WebhookEvent, "delivery-label")
assert event is not None
assert event.processed_status == "ignored"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ruff format --check .
ruff check .
pytest

Repository: ramimbo/mergework

Length of output: 183


Run the Python quality gates for this test change (pytest still missing).

  • ruff format --check .: pass
  • ruff check .: pass
  • pytest: not runnable in this environment (pytest: command not found, exit code 127). Re-run with pytest available so the changed routing behavior is exercised before merge.

@wangedmund77-cmyk
Copy link
Copy Markdown

Review note after inspecting app/webhooks/github.py and the new tests/test_webhook_event_routing.py: I do not see a blocker in the final shape.

The routing change is narrow: only issues and pull_request events continue into _handle_accepted_issue_label(...), while check_suite, push, and label now fall through to the existing ignored-event path. The tests cover all three ignored event types and also keep positive coverage for both paid paths (issues labeled and pull_request labeled), so the regression surface that previously returned missing_issue is covered without weakening accepted-label processing.

I also checked overlap with recent webhook tests in the current tree; this is a distinct routing regression test file rather than duplicating the existing accepted-label happy-path tests.

Copy link
Copy Markdown

@Thanhdn1984 Thanhdn1984 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review — #510

PR: #510
Author: @aglichandrap
Head SHA: e437a7fcb64847f9d7390f5f5ceb421ddd7ce2bd

Files Changed (2 files, +171/−1)

  • app/webhooks/github.py: Narrowed event routing from {"issues", "pull_request", "label", "check_suite", "push"}{"issues", "pull_request"}.
  • tests/test_webhook_event_routing.py: 170-line regression test covering all three removed event types (check_suite, push, label) as ignored, plus positive tests verifying issues and pull_request events still route to label handler and process payouts correctly.

CI Status

Quality/readiness/docs/image checks: completed/success
CodeRabbit: success

Code Review

  1. Fix is correct: check_suite, push, and label have different payload schemas than issues/pull_request — they lack top-level issue/pull_request fields, so routing them to _handle_accepted_issue_label() always resulted in missing_issue status. Removing them from the routing set is the right fix.
  2. Previous review feedback addressed: Latest commit adds label event test case (previously missing) and fixes Ruff formatting/import issues that were blocking CI.
  3. Test coverage is thorough: All three removed event types verified as ignored with WebhookEvent.processed_status == "ignored". Positive tests confirm issues labeled event still triggers bounty payout and pull_request labeled event routes correctly.
  4. CI green: All checks passing on current head.
  5. Clean merge: Mergeable state, no conflicts.

Verdict

APPROVE — Well-scoped fix with comprehensive regression coverage. Ready for merge.

@ramimbo
Copy link
Copy Markdown
Owner

ramimbo commented May 30, 2026

Maintainer triage 2026-05-30T05:56Z: holding for another useful current-head human review before merge. CI is green, the PR is mergeable, and the latest review addressed earlier blockers, but I am not merging it in this pass without the second useful current-head review.

Copy link
Copy Markdown

@chinook1001 chinook1001 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed current head e437a7fcb64847f9d7390f5f5ceb421ddd7ce2bd.

I approve this change. Narrowing webhook routing to issues and pull_request keeps the accepted-label payout path limited to payload shapes that actually carry an issue or PR object, while check_suite, push, and label now go through the generic ignored-event path and are still recorded for auditability.

Evidence checked:

  • Inspected app/webhooks/github.py, tests/test_webhook_event_routing.py, and the existing accepted-label coverage in tests/test_webhooks.py.
  • Verified all three removed event types (check_suite, push, label) are covered as ignored and assert persisted WebhookEvent.processed_status == "ignored".
  • Verified positive coverage remains for issues labels and pull_request labels, including actual payout balance assertions for linked bounty issues.
  • Checked that duplicate-delivery/idempotency behavior remains outside this routing change and is still covered by the existing webhook tests.
  • Checked hosted PR metadata: current head matches the reviewed commit, PR is mergeable/clean, and Quality, readiness, docs, and image checks is green.

Local validation:

  • ./.venv/bin/python -m pytest tests/test_webhook_event_routing.py tests/test_webhooks.py -q -> 23 passed.
  • ./.venv/bin/python -m ruff check app/webhooks/github.py tests/test_webhook_event_routing.py tests/test_webhooks.py -> passed.
  • ./.venv/bin/python -m ruff format --check app/webhooks/github.py tests/test_webhook_event_routing.py tests/test_webhooks.py -> already formatted.
  • git diff --check origin/main...HEAD -> clean.

Verdict: APPROVED — focused routing fix with regression coverage for ignored webhook event types and positive coverage for payout-capable events. No private data, credentials, wallet material, production mutation, price/exchange/bridge claims, or fabricated payout claims used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants