diff --git a/src/sentry/objectstore/types.py b/src/sentry/objectstore/types.py index 4a4ca525f829eb..478c6d8f3a12c3 100644 --- a/src/sentry/objectstore/types.py +++ b/src/sentry/objectstore/types.py @@ -6,5 +6,5 @@ class ObjectstoreUploadOptions(TypedDict): url: str scopes: list[tuple[str, str]] - # TODO: add authToken + authToken: str | None expirationPolicy: str diff --git a/src/sentry/preprod/api/endpoints/project_preprod_upload_options.py b/src/sentry/preprod/api/endpoints/project_preprod_upload_options.py index 8e3a8ee0056375..930cbb9ae417ec 100644 --- a/src/sentry/preprod/api/endpoints/project_preprod_upload_options.py +++ b/src/sentry/preprod/api/endpoints/project_preprod_upload_options.py @@ -16,6 +16,7 @@ from sentry.api.bases.project import ProjectEndpoint, ProjectReleasePermission from sentry.api.utils import generate_locality_url from sentry.models.project import Project +from sentry.objectstore import get_preprod_session from sentry.objectstore.types import ObjectstoreUploadOptions from sentry.utils.http import absolute_uri @@ -35,6 +36,7 @@ def get(self, request: Request, project: Project) -> Response: return Response({"detail": "Feature not enabled"}, status=403) organization = project.organization + session = get_preprod_session(org=organization.id, project=project.id) path = reverse( "sentry-api-0-organization-objectstore", @@ -53,6 +55,7 @@ def get(self, request: Request, project: Project) -> Response: ("org", str(organization.id)), ("project", str(project.id)), ], + authToken=session.mint_token(), expirationPolicy=format_expiration( TimeToLive(timedelta(days=30)) ), # Hardcoded for now, check with Objectstore before increasing diff --git a/tests/sentry/preprod/api/endpoints/test_project_preprod_upload_options.py b/tests/sentry/preprod/api/endpoints/test_project_preprod_upload_options.py index 9434f07c0b3f24..d59626dd1cec5a 100644 --- a/tests/sentry/preprod/api/endpoints/test_project_preprod_upload_options.py +++ b/tests/sentry/preprod/api/endpoints/test_project_preprod_upload_options.py @@ -1,3 +1,5 @@ +from unittest.mock import MagicMock, patch + from django.conf import settings from django.urls import reverse from rest_framework.test import APIClient @@ -16,7 +18,12 @@ def setUp(self) -> None: args=[self.org.slug, self.project.slug], ) - def test_returns_upload_options(self) -> None: + @patch("sentry.preprod.api.endpoints.project_preprod_upload_options.get_preprod_session") + def test_returns_upload_options(self, mock_get_session) -> None: + mock_session = MagicMock() + mock_session.mint_token.return_value = "fake-token" + mock_get_session.return_value = mock_session + with self.feature("organizations:preprod-snapshots"): response = self.client.get(self.url) @@ -27,9 +34,18 @@ def test_returns_upload_options(self) -> None: assert data["scopes"] == [("org", str(self.org.id)), ("project", str(self.project.id))] + assert data["authToken"] == "fake-token" + assert data["expirationPolicy"] == "ttl:30 days" - def test_objectstore_url_uses_region_endpoint(self) -> None: + mock_get_session.assert_called_once_with(org=self.org.id, project=self.project.id) + + @patch("sentry.preprod.api.endpoints.project_preprod_upload_options.get_preprod_session") + def test_objectstore_url_uses_region_endpoint(self, mock_get_session) -> None: + mock_session = MagicMock() + mock_session.mint_token.return_value = "fake-token" + mock_get_session.return_value = mock_session + with ( self.feature("organizations:preprod-snapshots"), self.options({"system.region-api-url-template": "https://{region}.testserver"}),