Skip to content

fix: guard against None actions in incidents and add deliver_feature_result to org seer rpc#119465

Draft
billyvg wants to merge 1 commit into
masterfrom
claude/serene-cannon-sy4paa
Draft

fix: guard against None actions in incidents and add deliver_feature_result to org seer rpc#119465
billyvg wants to merge 1 commit into
masterfrom
claude/serene-cannon-sy4paa

Conversation

@billyvg

@billyvg billyvg commented Jul 11, 2026

Copy link
Copy Markdown
Member

Fixes two production errors caught by automated monitoring.

Bug 1: SENTRY-5RDY — AttributeError in is_included when action is None

Severity: Medium (production error on alert rule update path)
Evidence: AttributeError: 'NoneType' object has no attribute 'get' at sentry/incidents/logic.py:1999 with local variable action: "None". Triggered by PUT /api/0/organizations/{org}/alert-rules/{id}/ when a trigger's actions list contains a None entry.

Fix: Guard is_included against None entries before calling .get(). A None action is excluded (returns False) rather than crashing. Also corrects the type annotation to Mapping[str, Any] | None.

Bug 2: SENTRY-5RDJRpcResolutionException: Unknown method deliver_feature_result

Severity: Medium (breaks Seer explorer feature result push-back to Sentry)
Evidence: RpcResolutionException raised in organization_seer_rpc.py:332 with rpc.referrer: explorer. Seer's explorer calls deliver_feature_result via ProductionProxyRpcClient which routes to /api/0/organizations/{org}/seer-rpc/ (the org-scoped endpoint), but the method was only registered in the internal seer_method_registry, not in public_org_seer_method_registry.

Seer Autofix root cause: "deliver_feature_result is registered in the global seer RPC registry but missing from the organization-scoped endpoint's registry."

Fix: Add deliver_feature_result to public_org_seer_method_registry. The method is safe here — it is already gated by the organizations:seer-public-rpc feature flag and org:read permission, and unknown feature_id values are silently ignored.

Session

https://claude.ai/code/session_01AMHSVfELZygxVFppMefZzm

Legal Boilerplate

Look, I get it. The entity doing business as "Sentry" was incorporated in the State of Delaware in 2015 as Functional Software, Inc. and is gonna need some rights from me in order to utilize my contributions in this here PR. So here's the deal: I retain all rights, title and interest in and to my contributions, and by keeping this boilerplate intact I confirm that Sentry can use, modify, copy, and redistribute my contributions, under Sentry's choice of terms.


Generated by Claude Code

…e_result to org seer rpc

Fixes two production errors:

1. SENTRY-5RDY: AttributeError in incidents/logic.py when action is None
   - `trigger.get("actions", [])` can yield None entries; is_included now
     returns False early instead of calling .get() on None.

2. SENTRY-5RDJ: RpcResolutionException for deliver_feature_result via org endpoint
   - deliver_feature_result was in the internal seer_method_registry but
     missing from public_org_seer_method_registry, causing 404s when
     ProductionProxyRpcClient (local Seer dev against prod) calls back
     to Sentry via the org-scoped endpoint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AMHSVfELZygxVFppMefZzm
@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label Jul 11, 2026
from sentry.seer.autofix.autofix_tools import get_error_event_details, get_profile_details
from sentry.seer.endpoints.registry import SeerRpcMethod, seer_rpc
from sentry.seer.endpoints.seer_rpc import (
deliver_feature_result,

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.

Read-only org member can trigger expensive night-shift writeback via org Seer RPC

Registering deliver_feature_result in the org-member Seer RPC registry lets any member with only org:read push a crafted night-shift result for a known run_uuid, triggering expensive trigger_autofix_agent runs, marking issues skipped, and writing fabricated triage rows within their org. Keep this writeback on the HMAC-authenticated Seer service endpoint (SeerRpcServiceEndpoint) only.

Evidence
  • The PR adds deliver_feature_result to public_org_seer_method_registry in organization_seer_rpc.py:164; that endpoint only enforces SeerRpcPermission (org:read) plus the organizations:seer-public-rpc flag and comments that it is "actually read only."
  • deliver_feature_result (seer_rpc.py:1004) dispatches feature_id="night_shift" to deliver_night_shift_result, which parses attacker-supplied result into TriageResponse and in _process_verdicts calls mark_skipped and trigger_autofix_agent for org groups (expensive/paid Seer operations) and bulk-creates SeerNightShiftRunResult rows with attacker-controlled reason text.
  • The delivery lookup is scoped to the caller's org (SeerNightShiftRunShard.objects.filter(seer_run__uuid=run_uuid, run__organization_id=organization_id)), so impact is intra-org, not cross-tenant.
  • A valid run_uuid is obtainable by members: SeerRunSerializer.serialize returns str(obj.uuid) as id, and filtered_runs_queryset always keeps project-less runs (night-shift shard SeerRuns), exposing the needed identifier.
Also found at 1 additional location
  • src/sentry/seer/endpoints/organization_seer_rpc.py:164-164

Identified by Warden security-review · FTM-DTG

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