Skip to content

Commit

Permalink
fix(deploys): Maintain backwards compatibility
Browse files Browse the repository at this point in the history
Changing the scope to `project:releases` breaks this endpoint for tokens that could previously specify specific projects for the deploy via this endpoint via `project:read` (in practice, `project:write` was also required, since the endpoint cannot be accessed only with `project:read`).
  • Loading branch information
szokeasaurusrex committed Sep 27, 2024
1 parent eaea926 commit 3becb44
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/sentry/api/endpoints/release_deploys.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class DeploySerializer(serializers.Serializer):
dateStarted = serializers.DateTimeField(required=False, allow_null=True)
dateFinished = serializers.DateTimeField(required=False, allow_null=True)
projects = serializers.ListField(
child=ProjectField(scope="project:releases", id_allowed=True),
child=ProjectField(scope=("project:read", "project:releases"), id_allowed=True),
required=False,
allow_empty=False,
)
Expand Down
13 changes: 11 additions & 2 deletions src/sentry/api/serializers/rest_framework/project.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from collections.abc import Collection

from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers
Expand All @@ -9,7 +11,12 @@

@extend_schema_field(field=OpenApiTypes.STR)
class ProjectField(serializers.Field):
def __init__(self, scope="project:write", id_allowed=False):
def __init__(self, scope: str | Collection[str] = "project:write", id_allowed: bool = False):
"""
The scope parameter specifies which permissions are required to access the project field.
If multiple scopes are provided, the project can be accessed when the user is authenticated with
any of the scopes.
"""
self.scope = scope
self.id_allowed = id_allowed
super().__init__()
Expand All @@ -27,6 +34,8 @@ def to_internal_value(self, data):
project = Project.objects.get(organization=self.context["organization"], slug=data)
except Project.DoesNotExist:
raise ValidationError("Invalid project")
if not self.context["access"].has_project_scope(project, self.scope):

scopes = (self.scope,) if isinstance(self.scope, str) else self.scope
if not self.context["access"].has_any_project_scope(project, scopes):
raise ValidationError("Insufficient access to project")
return project

0 comments on commit 3becb44

Please sign in to comment.