Skip to content

Migrate Seer handlers for code reviews to SCM listeners#112349

Draft
jacquev6 wants to merge 3 commits intomasterfrom
jacquev6/scm-platform/github-webhooks
Draft

Migrate Seer handlers for code reviews to SCM listeners#112349
jacquev6 wants to merge 3 commits intomasterfrom
jacquev6/scm-platform/github-webhooks

Conversation

@jacquev6
Copy link
Copy Markdown
Collaborator

@jacquev6 jacquev6 commented Apr 7, 2026

SCM listeners were introduced by #107441. This PR applies this new pattern to existing webhooks handlers for Seer code reviews.

I chose to delete handlers.py and create scm_listeners.py because modifying handlers.py in place would have made the diff unreadable (and the naming felt more appropriate).

In the new scm_listeners.py, there is code that does the equivalent of the old handlers.py (e.g. preflight and deduplication checks) as expected, and, more surprisingly, a part of src/sentry/integrations/github/webhook.py (e.g. finding the appropriate repo) that's not (yet?) implemented at SCM platform level.

I deleted some tests, e.g. in tests/sentry/seer/code_review/webhooks/test_check_run.py, because these cases are now caught early by the SCM platform's MsgSpec models.

Moving import GithubActionHandler (used for its side-effects) from src/sentry/integrations/github/__init__.py to src/sentry_plugins/github/client.py was required to allow importing .integrations.github before initialize_app is called.

I was able to test this change end-to-end locally, by creating a pull request on a test repository and observing that the webhook is called, and leaves an 👀 reaction on the new PR. But to do that, I had to temporarily:

  • disable the "rollout" check in src/sentry/scm/private/stream_producer.py (mostly because I don't know how to configure my local env to indeed rollout the SCM stream feature). We need to actually rollout the feature before deploying this PR.
  • disable all preflight checks in src/sentry/seer/code_review/preflight.py because my test repo is not enrolled with Seer
  • remove .delay in produce_to_listener in src/sentry/scm/private/ipc.py because the delayed function was never called in my dev env. This failed silently, so it's somewhat concerning and needs to be discussed in stand-up (Did the IPC fail? Is the worker even running?).

@jacquev6 jacquev6 requested a review from cmanallen April 7, 2026 12:30
@jacquev6 jacquev6 requested review from a team as code owners April 7, 2026 12:30
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Apr 7, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 7, 2026

Backend Test Failures

Failures on 765de1a in this run:

tests/sentry/integrations/github_enterprise/test_webhooks.py::PullRequestEventWebhook::test_code_review_skipped_for_github_enterpriselog
[gw1] linux -- Python 3.13.1 /home/runner/work/sentry/sentry/.venv/bin/python3
/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/unittest/mock.py:1421: in patched
    with self.decoration_helper(patched,
/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/contextlib.py:141: in __enter__
    return next(self.gen)
/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/unittest/mock.py:1403: in decoration_helper
    arg = exit_stack.enter_context(patching)
/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/contextlib.py:530: in enter_context
    result = _enter(cm)
/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/unittest/mock.py:1479: in __enter__
    self.target = self.getter()
/opt/hostedtoolcache/Python/3.13.1/x64/lib/python3.13/pkgutil.py:528: in resolve_name
    result = getattr(result, p)
E   AttributeError: module 'sentry.seer.code_review.webhooks' has no attribute 'handlers'

Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Action handler registration moved to unreliable import location
    • I restored the GitHub handler side-effect import to sentry.integrations.github.__init__ and removed the on-demand plugin-client import so action registration occurs reliably at startup.

Create PR

Or push these changes by commenting:

@cursor push fbedbaec56
Preview (fbedbaec56)
diff --git a/src/sentry/integrations/github/__init__.py b/src/sentry/integrations/github/__init__.py
--- a/src/sentry/integrations/github/__init__.py
+++ b/src/sentry/integrations/github/__init__.py
@@ -1,5 +1,6 @@
 from sentry.rules import rules
 
 from .actions.create_ticket import GitHubCreateTicketAction
+from .handlers import GithubActionHandler  # noqa: F401
 
 rules.add(GitHubCreateTicketAction)

diff --git a/src/sentry_plugins/github/client.py b/src/sentry_plugins/github/client.py
--- a/src/sentry_plugins/github/client.py
+++ b/src/sentry_plugins/github/client.py
@@ -3,7 +3,6 @@
 import time
 
 from sentry import options
-from sentry.integrations.github import handlers  # noqa: F401
 from sentry.integrations.github.constants import GITHUB_API_ACCEPT_HEADER
 from sentry.integrations.services.integration.model import RpcIntegration
 from sentry.utils import jwt

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

from sentry.rules import rules

from .actions.create_ticket import GitHubCreateTicketAction
from .handlers import GithubActionHandler # noqa: F401,F403
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Action handler registration moved to unreliable import location

High Severity

The GithubActionHandler side-effect import was moved from sentry/integrations/github/__init__.py to sentry_plugins/github/client.py. This new location is only loaded on-demand, preventing the handler from reliably registering during startup. Consequently, GitHub workflow engine actions, like ticket creation, will not function.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 2f4ffa0. Configure here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This statement is concerning, but importing .integrations.github.handlers in __init__.py is incompatible with importing the listeners statically in .../scm/stream.py. This all boils down to sentry/integrations/jira/client.py calling absolute_url at module level, which requires initialize_app to have been called.

I checked the original stacktrace when action_handler_registry.register was called for GithubActionHandler and made sure that it's still registered "during startup".

It might be worth defining "during startup": I'm talking about the startup of the backend web server. If GithubActionHandler should be registered to the action_handler_registry for other processes, their startup sequence must indeed be modified in a similar way.

The compromise I chose can be revisited by a human with a more effective brain than mine.

_handle_pr_webhook_for_autofix_processor,
code_review_handle_webhook_event,
)
WEBHOOK_EVENT_PROCESSORS = (_handle_pr_webhook_for_autofix_processor,)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: Seer code review functionality will silently fail upon deployment because the new async processing path is gated by a feature flag that is disabled by default.
Severity: CRITICAL

Suggested Fix

To prevent a silent outage, either remove the feature flag gating produce_event_to_scm_stream to enable the new path by default, or ensure the deployment process strictly requires enabling the sentry.scm.stream.rollout option beforehand. A safer approach would be to make the new path the default and remove the flag dependency.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: src/sentry/integrations/github/webhook.py#L847

Potential issue: The synchronous webhook processor `code_review_handle_webhook_event` is
removed and replaced with an asynchronous path gated by the `sentry.scm.stream.rollout`
feature flag. This flag is disabled by default. If the PR is deployed without explicitly
enabling this flag, all Seer code review functionality (PR analysis, check run
reactions, etc.) will silently stop working. The webhooks will continue to return
successful HTTP 204 responses, masking the fact that no processing is occurring.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This statement is true, and was anticipated in bold font in the PR description.

Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0e25233. Configure here.


# Code review is only supported on GitHub Cloud, not GitHub Enterprise on-prem.
if integration.provider == IntegrationProviderSlug.GITHUB_ENTERPRISE:
return
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unreachable GitHub Enterprise provider check is dead code

Low Severity

The check for integration.provider == IntegrationProviderSlug.GITHUB_ENTERPRISE on line 79 is unreachable. The integration_service.organization_contexts call on line 64 already filters integrations to GITHUB.value, so a GitHub Enterprise integration would never be returned, making this check dead code.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 0e25233. Configure here.

Copy link
Copy Markdown
Member

@armenzg armenzg left a comment

Choose a reason for hiding this comment

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

Makes sense 👍🏻

Comment on lines +150 to +165
def handle_check_run_via_scm_stream(e: CheckRunEvent) -> None:
delivery_id = e.subscription_event["extra"].get("github_delivery_id")
assert delivery_id is None or isinstance(delivery_id, str)
if delivery_id and not _is_first_delivery(delivery_id):
logger.warning("github.scm_listener.duplicate_delivery_skipped")
return

for integration, org, repo, raw_event, _preflight in _find_allowed_repo(
e.subscription_event, GithubWebhookType.CHECK_RUN
):
tags = _set_tags(raw_event, GithubWebhookType.CHECK_RUN, org, integration, delivery_id)
handle_check_run_event(
github_event=GithubWebhookType.CHECK_RUN,
event=raw_event,
tags=tags,
)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do you have ideas on how this will look as we add support for more providers?

@jacquev6
Copy link
Copy Markdown
Collaborator Author

jacquev6 commented Apr 9, 2026

The SCM team has decided to start with GitLab and do GitHub later. I'm converting this PR to draft until then.

@jacquev6 jacquev6 marked this pull request as draft April 9, 2026 08:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants