Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 8 additions & 11 deletions src/sentry/seer/signed_seer_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from sentry.net.http import connection_from_url
from sentry.utils import metrics
from sentry.viewer_context import ViewerContext, get_viewer_context
from sentry.viewer_context import ViewerContext, encode_viewer_context, get_viewer_context


class SeerViewerContext(TypedDict, total=False):
Expand Down Expand Up @@ -138,18 +138,15 @@ def make_signed_seer_api_request(

resolved = _resolve_viewer_context(viewer_context)
if resolved:
if settings.SEER_API_SHARED_SECRET:
try:
context_bytes = orjson.dumps(resolved.serialize())
context_signature = sign_viewer_context(context_bytes)
headers["X-Viewer-Context"] = context_bytes.decode("utf-8")
headers["X-Viewer-Context-Signature"] = context_signature
except Exception:
logger.exception("Failed to serialize viewer context for call to Seer.")
else:
try:
headers["X-Viewer-Context"] = encode_viewer_context(resolved)
except ValueError:
logger.warning(
"settings.SEER_API_SHARED_SECRET is not set. Unable to sign viewer context for call to Seer."
"viewer_context_jwt.no_signing_key",
extra={"msg": "No key available to sign viewer context JWT."},
)
except Exception:
logger.exception("Failed to encode viewer context JWT for call to Seer.")
Comment thread
cursor[bot] marked this conversation as resolved.

options: dict[str, Any] = {}
if timeout:
Expand Down
32 changes: 13 additions & 19 deletions tests/sentry/event_manager/test_severity.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from __future__ import annotations

import hashlib
import hmac
import uuid
from typing import Any
from unittest.mock import MagicMock, patch
Expand Down Expand Up @@ -88,23 +86,19 @@ def test_error_event_simple(self, mock_urlopen: MagicMock) -> None:
override_settings(SEER_API_SHARED_SECRET="some-secret"),
):
_get_severity_score(event)
viewer_context_bytes = orjson.dumps(
{"actor_type": "unknown", "organization_id": self.project.organization_id}
)
mock_urlopen.assert_called_with(
"POST",
"/v0/issues/severity-score",
body=orjson.dumps(payload),
headers={
"content-type": "application/json;charset=utf-8",
"Authorization": f"Rpcsignature rpc0:{hmac.new(b'some-secret', orjson.dumps(payload), hashlib.sha256).hexdigest()}",
"X-Viewer-Context": viewer_context_bytes.decode("utf-8"),
"X-Viewer-Context-Signature": hmac.new(
b"some-secret", viewer_context_bytes, hashlib.sha256
).hexdigest(),
},
timeout=options.get("issues.severity.seer-timeout", settings.SEER_SEVERITY_TIMEOUT),
)
call_kwargs = mock_urlopen.call_args
assert call_kwargs[0] == ("POST", "/v0/issues/severity-score")
assert call_kwargs[1]["body"] == orjson.dumps(payload)
headers = call_kwargs[1]["headers"]
assert headers["content-type"] == "application/json;charset=utf-8"
assert "Authorization" in headers
assert "X-Viewer-Context-Signature" not in headers
# ViewerContext is now a JWT
from sentry.viewer_context import decode_viewer_context

vc = decode_viewer_context(headers["X-Viewer-Context"], key="some-secret")
assert vc.organization_id == self.project.organization_id
assert vc.actor_type.value == "unknown"

@patch(
"sentry.event_manager.severity_connection_pool.urlopen",
Expand Down
Loading