From abb472e83252aa8a18ab134e8f6b009758469249 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Tue, 7 Feb 2023 14:24:05 +0100 Subject: [PATCH 1/2] feat(loader): Add boilerplate for js sdk dynamic loader --- src/sentry/web/frontend/js_sdk_dynamic_loader.py | 5 +++++ src/sentry/web/urls.py | 7 +++++++ .../web/frontend/test_js_sdk_dynamic_loader.py | 13 +++++++++++++ 3 files changed, 25 insertions(+) create mode 100644 src/sentry/web/frontend/js_sdk_dynamic_loader.py create mode 100644 tests/sentry/web/frontend/test_js_sdk_dynamic_loader.py diff --git a/src/sentry/web/frontend/js_sdk_dynamic_loader.py b/src/sentry/web/frontend/js_sdk_dynamic_loader.py new file mode 100644 index 00000000000000..3fbb00c26ef511 --- /dev/null +++ b/src/sentry/web/frontend/js_sdk_dynamic_loader.py @@ -0,0 +1,5 @@ +from sentry.web.frontend.base import BaseView + + +class JavaScriptSdkDynamicLoader(BaseView): + pass diff --git a/src/sentry/web/urls.py b/src/sentry/web/urls.py index 2983f23c9df8a4..49a1b5402409b1 100644 --- a/src/sentry/web/urls.py +++ b/src/sentry/web/urls.py @@ -23,6 +23,7 @@ from sentry.web.frontend.group_tag_export import GroupTagExportView from sentry.web.frontend.home import HomeView from sentry.web.frontend.idp_email_verification import AccountConfirmationView +from sentry.web.frontend.js_sdk_dynamic_loader import JavaScriptSdkDynamicLoader from sentry.web.frontend.js_sdk_loader import JavaScriptSdkLoader from sentry.web.frontend.mailgun_inbound_webhook import MailgunInboundWebhookView from sentry.web.frontend.newest_performance_issue import NewestPerformanceIssueView @@ -116,6 +117,12 @@ JavaScriptSdkLoader.as_view(), name="sentry-js-sdk-loader", ), + # Javascript SDK Loader + url( + r"^js-sdk-loader/(?P[^/\.]+)(?:(?P\.min))?\.js$", + JavaScriptSdkDynamicLoader.as_view(), + name="sentry-js-sdk-loader", + ), # Versioned API url(r"^api/0/", include("sentry.api.urls")), # Legacy unversioned endpoints diff --git a/tests/sentry/web/frontend/test_js_sdk_dynamic_loader.py b/tests/sentry/web/frontend/test_js_sdk_dynamic_loader.py new file mode 100644 index 00000000000000..0f92a61beb8c37 --- /dev/null +++ b/tests/sentry/web/frontend/test_js_sdk_dynamic_loader.py @@ -0,0 +1,13 @@ +# import pytest + +from sentry.testutils import TestCase + + +class JavaScriptSdkDynamicLoaderTest(TestCase): + def test_noop_no_pub_key(self): + # When given no public key, respond with the noop template + pass + + def test_noop(self): + # When given a public key, but no default SDK URL, respond with the noop template + pass From 9c3fb45ff3d2b54f4c6a6c2e3f2af1a0f97181cd Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Thu, 9 Feb 2023 14:24:06 +0100 Subject: [PATCH 2/2] more stuff --- src/sentry/conf/server.py | 1 + .../web/frontend/js_sdk_dynamic_loader.py | 66 ++++++++++++++++++- .../frontend/test_js_sdk_dynamic_loader.py | 20 +++++- 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/sentry/conf/server.py b/src/sentry/conf/server.py index 7717fda44687e9..3dc7c562ebe384 100644 --- a/src/sentry/conf/server.py +++ b/src/sentry/conf/server.py @@ -2530,6 +2530,7 @@ def build_cdc_postgres_init_db_volume(settings): # - 'https://browser.sentry-cdn.com/6.19.7/bundle.min.js' will stay the same. JS_SDK_LOADER_DEFAULT_SDK_URL = "" + # block domains which are generally used by spammers -- keep this configurable # in case a self-hosted install wants to allow it INVALID_EMAIL_ADDRESS_PATTERN = re.compile(r"\@qq\.com$", re.I) diff --git a/src/sentry/web/frontend/js_sdk_dynamic_loader.py b/src/sentry/web/frontend/js_sdk_dynamic_loader.py index 3fbb00c26ef511..20a48c81f0a006 100644 --- a/src/sentry/web/frontend/js_sdk_dynamic_loader.py +++ b/src/sentry/web/frontend/js_sdk_dynamic_loader.py @@ -1,5 +1,69 @@ +from typing import Optional, Tuple, TypedDict + +from rest_framework.request import Request +from rest_framework.response import Response + +from sentry.loader.browsersdkversion import get_browser_sdk_version +from sentry.models import Project, ProjectKey from sentry.web.frontend.base import BaseView +class SdkConfig(TypedDict): + dsn: str + + +class LoaderContext(TypedDict): + config: SdkConfig + jsSdkUrl: Optional[str] + publicKey: Optional[str] + + class JavaScriptSdkDynamicLoader(BaseView): - pass + auth_required = False + + # Do not let an organization load trigger session, breaking Vary header. + # TODO: This view should probably not be a subclass of BaseView if it doesn't actually use the + # large amount of organization related support utilities, but that ends up being a large refactor. + def determine_active_organization(self, request: Request, organization_slug=None) -> None: + pass + + def _get_bundle_kind_modifier(self) -> str: + """Returns a string that is used to modify the bundle name""" + bundle_kind_modifier = "" + + # if tracing + bundle_kind_modifier += ".tracing" + + # if replay + bundle_kind_modifier += ".replay" + + # if es5 + bundle_kind_modifier += ".es5" + + # if debug + bundle_kind_modifier += ".debug" + + return bundle_kind_modifier + + def _get_context(self, key: str) -> Tuple[LoaderContext, Optional[str], Optional[str]]: + """Sets context information needed to render the loader""" + if not key: + return ({}, None, None) + + sdk_version = get_browser_sdk_version(key) + + # TODO(abhi): Right now this loader only supports returning es6 JS bundles. + # We may want to re-evaluate this. + + return ({}, sdk_version, None) + + def get(self, request: Request, public_key: str, minified: str) -> Response: + """Returns a JS file that dynamically loads the SDK based on project settings""" + key = None + + try: + key = ProjectKey.objects.get_from_cache(public_key=public_key) + except ProjectKey.DoesNotExist: + pass + else: + key.project = Project.objects.get_from_cache(id=key.project_id) diff --git a/tests/sentry/web/frontend/test_js_sdk_dynamic_loader.py b/tests/sentry/web/frontend/test_js_sdk_dynamic_loader.py index 0f92a61beb8c37..934a51b0d8029d 100644 --- a/tests/sentry/web/frontend/test_js_sdk_dynamic_loader.py +++ b/tests/sentry/web/frontend/test_js_sdk_dynamic_loader.py @@ -1,9 +1,15 @@ -# import pytest +import pytest +from django.conf import settings from sentry.testutils import TestCase class JavaScriptSdkDynamicLoaderTest(TestCase): + @pytest.fixture(autouse=True) + def set_settings(self): + settings.JS_SDK_LOADER_SDK_VERSION = "7.36.0" + settings.JS_SDK_LOADER_DEFAULT_SDK_URL = "https://browser.sentry-cdn.com/%s/bundle%s.min.js" + def test_noop_no_pub_key(self): # When given no public key, respond with the noop template pass @@ -11,3 +17,15 @@ def test_noop_no_pub_key(self): def test_noop(self): # When given a public key, but no default SDK URL, respond with the noop template pass + + def test_no_replace(self): + # When given a public key, and a default SDK URL, but the SDK version is not set, respond with the noop template + pass + + def test_renders_js_loader(self): + # When given a public key, and a default SDK URL, and the SDK version is set, respond with the js loader template + pass + + def test_minified(self): + # When given a public key, and a default SDK URL, and the SDK version is set, respond with the minified js loader template + pass