Skip to content

Commit 18f7c5e

Browse files
grichaclaude
andauthored
feat(integrations): Propagate ViewerContext in Jira Cloud webhook (#112412)
## Summary - Wraps the per-org iteration in `handle_status_change` with `webhook_viewer_context` so downstream code has access to the current organization identity via the ViewerContext contextvar. - Gated behind the `viewer-context.enabled` option (no-op when disabled). - Part of the ViewerContext RFC rollout for webhook handlers. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 136b8b6 commit 18f7c5e

File tree

2 files changed

+41
-10
lines changed

2 files changed

+41
-10
lines changed

src/sentry/integrations/jira/utils/api.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from sentry.integrations.services.integration import integration_service
1111
from sentry.integrations.services.integration.model import RpcIntegration
1212
from sentry.integrations.utils.sync import sync_group_assignee_inbound
13+
from sentry.integrations.utils.webhook_viewer_context import webhook_viewer_context
1314
from sentry.shared_integrations.exceptions import ApiError
1415

1516
from ...mixins.issues import IssueSyncIntegration
@@ -109,16 +110,17 @@ def handle_status_change(integration: RpcIntegration, data: Mapping[str, Any]) -
109110

110111
result = integration_service.organization_contexts(integration_id=integration.id)
111112
for oi in result.organization_integrations:
112-
install = integration.get_installation(organization_id=oi.organization_id)
113-
if isinstance(install, IssueSyncIntegration):
114-
install.sync_status_inbound(
115-
issue_key, {"changelog": changelog, "issue": data["issue"]}
116-
)
117-
else:
118-
lifecycle.record_halt(
119-
ProjectManagementHaltReason.SYNC_NON_SYNC_INTEGRATION_PROVIDED,
120-
extra=log_context,
121-
)
113+
with webhook_viewer_context(oi.organization_id):
114+
install = integration.get_installation(organization_id=oi.organization_id)
115+
if isinstance(install, IssueSyncIntegration):
116+
install.sync_status_inbound(
117+
issue_key, {"changelog": changelog, "issue": data["issue"]}
118+
)
119+
else:
120+
lifecycle.record_halt(
121+
ProjectManagementHaltReason.SYNC_NON_SYNC_INTEGRATION_PROVIDED,
122+
extra=log_context,
123+
)
122124

123125

124126
def handle_jira_api_error(error: ApiError, message: str = "") -> Mapping[str, str] | None:

tests/sentry/integrations/jira/test_webhooks.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
from sentry.organizations.services.organization.serial import serialize_rpc_organization
1717
from sentry.shared_integrations.exceptions import ApiError
1818
from sentry.testutils.cases import APITestCase, TestCase
19+
from sentry.testutils.helpers.options import override_options
20+
from sentry.viewer_context import ActorType, get_viewer_context
1921

2022
TOKEN = "JWT anexampletoken"
2123

@@ -164,6 +166,33 @@ def test_simple_status_sync_inbound(self, mock_sync_status_inbound: MagicMock) -
164166
},
165167
)
166168

169+
@override_options({"viewer-context.enabled": True})
170+
def test_status_sync_sets_viewer_context(self) -> None:
171+
captured_contexts: list = []
172+
173+
def capture_viewer_context(*args, **kwargs):
174+
captured_contexts.append(get_viewer_context())
175+
176+
with (
177+
patch(
178+
"sentry.integrations.jira.webhooks.issue_updated.get_integration_from_jwt",
179+
return_value=self.integration,
180+
),
181+
patch.object(
182+
IssueSyncIntegration,
183+
"sync_status_inbound",
184+
side_effect=capture_viewer_context,
185+
),
186+
):
187+
data = StubService.get_stub_data("jira", "edit_issue_status_payload.json")
188+
self.get_success_response(**data, extra_headers=dict(HTTP_AUTHORIZATION=TOKEN))
189+
190+
assert len(captured_contexts) == 1
191+
ctx = captured_contexts[0]
192+
assert ctx is not None
193+
assert ctx.organization_id == self.organization.id
194+
assert ctx.actor_type == ActorType.INTEGRATION
195+
167196
@patch("sentry_sdk.set_tag")
168197
@patch("sentry.integrations.utils.scope.bind_organization_context")
169198
def test_adds_context_data(

0 commit comments

Comments
 (0)