feat(hybridcloud): Propagate ViewerContext through cross-silo RPC#112248
feat(hybridcloud): Propagate ViewerContext through cross-silo RPC#112248
Conversation
| return settings.RPC_TIMEOUT | ||
|
|
||
| def _send_to_remote_silo(self, use_test_client: bool) -> Any: | ||
| from sentry.viewer_context import get_viewer_context |
There was a problem hiding this comment.
Is there a cyclic import here?
Pack ViewerContext into the RPC meta dict on the sending side and restore it via viewer_context_scope on the receiving side. This closes the gap where cross-silo RPC handlers had no ViewerContext despite the original request having one. Uses the existing reserved meta key in the RPC wire format. Backwards compatible — old callers send empty meta, receivers treat missing viewer_context as None. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…port Wrap ViewerContext.deserialize() in try/except to return ParseError on malformed viewer_context data, matching the existing AuthenticationContext error handling pattern. Move get_viewer_context import to top-level in service.py since there is no circular dependency. Addresses PR review feedback from markstory. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
request.data.get("meta", {}) returns None when the payload contains
"meta": null, since the default only applies for missing keys. Use
`or {}` to handle both missing and null values, preventing an
AttributeError on the subsequent .get() call.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
efc3b5a to
1fa13d4
Compare
Backend Test FailuresFailures on
|
The RPC endpoint ran inside ViewerContextMiddleware, which sets a ViewerContext for the transport request itself. When no viewer_context was provided in meta, nullcontext() left the middleware's context active, leaking incorrect identity to the RPC handler. Always enter viewer_context_scope with either the caller's deserialized context or an empty ViewerContext(actor_type=UNKNOWN) to override the middleware's context. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d1e6d1a. Configure here.
|
|
||
| try: | ||
| with auth_context.applied_to_request(request): | ||
| with viewer_context_scope(vc), auth_context.applied_to_request(request): |
There was a problem hiding this comment.
Default ViewerContext always set, breaking None semantics
Low Severity
When no viewer_context is present in meta, the code unconditionally creates a default ViewerContext() and enters viewer_context_scope(vc). This means get_viewer_context() inside RPC dispatch now returns a non-None ViewerContext instance instead of None. Downstream, _resolve_viewer_context in signed_seer_api.py checks vc is None — a default ViewerContext() is truthy and not None, causing Seer API calls from RPC handlers to start sending X-Viewer-Context headers with {"actor_type":"unknown"} where no header was previously sent. Wrapping in viewer_context_scope only when vc_data is present would preserve the prior None semantics.
Reviewed by Cursor Bugbot for commit d1e6d1a. Configure here.
There was a problem hiding this comment.
The intention is for viewer context to be truthy, the issue is on the seer rpc side and I'll fix it there.
…12248) Pack ViewerContext into the RPC `meta` dict on the sending side (`_send_to_remote_silo`) and restore it via `viewer_context_scope` on the receiving side (`InternalRpcServiceEndpoint`). Previously, cross-silo RPC handlers had no ViewerContext — the middleware saw RPC signature auth, not the original user. The real user identity was only available through `AuthenticationContext` (which most RPC calls don't pass). Now the contextvar is automatically propagated through `meta`, which was already reserved in the wire format for exactly this kind of use. Backwards compatible — old callers send `meta: {}`, receivers treat missing `viewer_context` as `None`. Also adds `ViewerContext.deserialize()` as the inverse of `serialize()`. Part of the [ViewerContext RFC](https://www.notion.so/sentry/RFC-Unified-ViewerContext-via-ContextVar-32f8b10e4b5d81988625cb5787035e02). --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>


Pack ViewerContext into the RPC
metadict on the sending side (_send_to_remote_silo) and restore it viaviewer_context_scopeon the receiving side (InternalRpcServiceEndpoint).Previously, cross-silo RPC handlers had no ViewerContext — the middleware saw RPC signature auth, not the original user. The real user identity was only available through
AuthenticationContext(which most RPC calls don't pass). Now the contextvar is automatically propagated throughmeta, which was already reserved in the wire format for exactly this kind of use.Backwards compatible — old callers send
meta: {}, receivers treat missingviewer_contextasNone.Also adds
ViewerContext.deserialize()as the inverse ofserialize().Part of the ViewerContext RFC.