From bb8de3171749e6f5ddf7703179273d2d972dd898 Mon Sep 17 00:00:00 2001 From: Klaas van Schelven Date: Fri, 10 Nov 2023 17:50:53 +0100 Subject: [PATCH] Sentry DSN parsing --- bugsink/settings.py | 1 + compat/__init__.py | 0 compat/dsn.py | 36 ++++++++++++++++++++++++++++++++++++ compat/tests.py | 29 +++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+) create mode 100644 compat/__init__.py create mode 100644 compat/dsn.py create mode 100644 compat/tests.py diff --git a/bugsink/settings.py b/bugsink/settings.py index 8a40282..b2b228b 100644 --- a/bugsink/settings.py +++ b/bugsink/settings.py @@ -35,6 +35,7 @@ INSTALLED_APPS = [ 'tailwind', 'theme', + 'compat', 'projects', 'ingest', 'issues', diff --git a/compat/__init__.py b/compat/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/compat/dsn.py b/compat/dsn.py new file mode 100644 index 0000000..d4a489b --- /dev/null +++ b/compat/dsn.py @@ -0,0 +1,36 @@ +import urllib.parse + + +def _get_url(sentry_dsn, ingest_method): + parts = urllib.parse.urlsplit(sentry_dsn) + + # note: we don't replicate Sentry's requirement that a project id must be an int + path_before_api, project_id = parts.path.rsplit("/", 1) + + return ( + parts.scheme + "://" + parts.hostname + (":" + str(parts.port) if parts.port else "") + + path_before_api + "/api/" + project_id + "/" + ingest_method + "/") + + +def get_store_url(sentry_dsn): + # In sentry's-lingo 'store' just means 'ingest events one by one' + return _get_url(sentry_dsn, "store") + + +def get_envelope_url(sentry_dsn): + return _get_url(sentry_dsn, "envelope") + + +def get_header_value(sentry_dsn): + parts = urllib.parse.urlsplit(sentry_dsn) + + return "Sentry " + ", ".join("%s=%s" % (key, value) for key, value in { + "sentry_key": parts.username, + + # this refers to the Sentry Protocol Version. It's hard to find documentation about this, but the current (late + # 2023) value is 7, and this has been the sentry-python's version since its Initial commit in June 2018. + "sentry_version": "7", + + # sentry_secret is deprecated, as mentioned elsewhere in the code. + # sentry_client ... may be useful, let's figure that out later TODO + }.items()) diff --git a/compat/tests.py b/compat/tests.py new file mode 100644 index 0000000..f032f72 --- /dev/null +++ b/compat/tests.py @@ -0,0 +1,29 @@ +from unittest import TestCase + +from .dsn import get_store_url, get_envelope_url, get_header_value + + +class DsnTestCase(TestCase): + def test_get_store_url(self): + self.assertEquals( + "https://hosted.bugsink/api/1/store/", + get_store_url("https://public_key@hosted.bugsink/1")) + + self.assertEquals( + "https://hosted.bugsink/some/path/api/1/store/", + get_store_url("https://public_key@hosted.bugsink/some/path/1")) + + def test_get_store_url_non_default_port(self): + self.assertEquals( + "http://hosted.bugsink:8000/api/1/store/", + get_store_url("http://public_key@hosted.bugsink:8000/1")) + + def test_get_envelope_url(self): + self.assertEquals( + "https://hosted.bugsink/api/1/envelope/", + get_envelope_url("https://public_key@hosted.bugsink/1")) + + def test_get_header_value(self): + self.assertEquals( + "Sentry sentry_key=public_key, sentry_version=7", + get_header_value("https://public_key@hosted.bugsink/1"))