Skip to content

feat(sentry-apps): Validate org membership before sending webhook disable emails#114799

Merged
Christinarlong merged 9 commits into
masterfrom
Christinarlong/org-membership-rpc
May 7, 2026
Merged

feat(sentry-apps): Validate org membership before sending webhook disable emails#114799
Christinarlong merged 9 commits into
masterfrom
Christinarlong/org-membership-rpc

Conversation

@Christinarlong
Copy link
Copy Markdown
Contributor

@Christinarlong Christinarlong commented May 4, 2026

Summary

  • Adds an RPC to app_service to get the first valid email (is org member and verified, else an owner)

Context

In #114115 , @GabeVillalobos raised a good point where it's possible the creator of an app may not be apart of an organization (removed, deleted etc.) so we should validate org membership. Since webhooks are primarily sent from cell/region side, we need RPCs to do the validation which is all on the User/UserEmail/OrganizationMemberMapping models which are all in control. So to reduce the RPC calls we're consolidating to 1 specific RPC.

Changes

  • Adds get_notification_emails_for_sentry_app which either
    • returns the given creator_label (the creator of the app's email) if they are active, verified and an org member (_validate_creator_email)
    • If the creator email is not valid then we get the first email from an org owner (_get_org_owner_email)

…able emails

Add RPC method get_notification_emails_for_sentry_app to app_service
that validates the creator email against UserEmail (verified, active,
org member) before sending circuit breaker notifications. Falls back
to org owner email when the creator is no longer a valid recipient.

Previously, webhook disable emails were sent to sentry_app.creator_label
without verifying the creator was still an org member — a security risk
if the creator had since left the organization.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label May 4, 2026
Christinarlong and others added 2 commits May 4, 2026 16:18
Stop mocking the entire NotificationService class. Instead, patch only
notify_async and enable the notification-platform feature flag with
rollout options, matching the pattern in notification platform tests.

Also removes _get_notification_recipients mocks so integration tests
exercise the real RPC recipient resolution path.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
The caller already has the sentry_app with owner_id, so pass
organization_id directly instead of sentry_app_id + re-querying.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
@Christinarlong Christinarlong marked this pull request as ready for review May 4, 2026 23:45
@Christinarlong Christinarlong requested review from a team as code owners May 4, 2026 23:45
@Christinarlong Christinarlong requested review from a team and GabeVillalobos May 4, 2026 23:56
Comment thread src/sentry/sentry_apps/services/app/impl.py Outdated
Comment thread src/sentry/sentry_apps/services/app/impl.py Outdated
Comment thread src/sentry/sentry_apps/services/app/impl.py Outdated
Christinarlong and others added 3 commits May 6, 2026 12:41
Rename to _is_valid_creator_email and return bool instead of list[str].
The caller now wraps the email in a list only when validation passes.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
_get_org_owner_emails now returns the full list so the RPC layer
doesn't impose a limit. The webhook caller truncates to 1 recipient
to avoid spamming when there are many owners.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
The limit-to-1 decision belongs in the notification sender, not the
recipient resolver.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Comment on lines +146 to +150
if not recipient_emails:
logger.info(
"sentry_app.webhook.circuit_breaker.no_recipients",
extra={"slug": sentry_app.slug, "owner_id": sentry_app.owner_id},
)
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.

I missed this in my earlier review, but we need to split this into its own PR. RPC service methods need to be deployed before usage is rolled out unless this is behind a FF

Revert webhooks.py and test changes — RPC methods must be deployed
before callers are rolled out. This PR now only contains the RPC
service definition; webhook usage will follow in a separate PR.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Comment thread src/sentry/sentry_apps/services/app/impl.py
_get_org_owner_emails was reading User.email directly, which is not
guaranteed to be verified. Now joins through UserEmail with
is_verified=True to match the same verification standard used by
_is_valid_creator_email.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
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.

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 5a4e45e. Configure here.

user__is_active=True,
user__emails__is_verified=True,
).values_list("user__emails__email", flat=True)
)
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.

Query returns all verified emails per owner, causing duplicates

Medium Severity

_get_org_owner_emails joins through user__emails and uses values_list("user__emails__email", flat=True), which produces one row per verified UserEmail per org owner. If an owner has multiple verified email addresses, all of them are returned. This contradicts the PR description which says the function returns "the first email from an org owner," and could result in duplicate notifications being sent to the same person at different addresses.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 5a4e45e. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ill change the pr description 💀

…pp RPC

Test the RPC implementation directly covering: valid creator,
non-member fallback, unverified email fallback, username without @,
no valid recipients, inactive creator, and unverified owner exclusion.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
@Christinarlong Christinarlong merged commit 543fb56 into master May 7, 2026
73 checks passed
@Christinarlong Christinarlong deleted the Christinarlong/org-membership-rpc branch May 7, 2026 23:01
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.

2 participants