|
2 | 2 |
|
3 | 3 | from django.urls import reverse
|
4 | 4 |
|
| 5 | +from sentry.models.apitoken import ApiToken |
5 | 6 | from sentry.models.deploy import Deploy
|
6 | 7 | from sentry.models.environment import Environment
|
7 | 8 | from sentry.models.release import Release
|
8 | 9 | from sentry.models.releaseprojectenvironment import ReleaseProjectEnvironment
|
| 10 | +from sentry.silo.base import SiloMode |
9 | 11 | from sentry.testutils.cases import APITestCase
|
| 12 | +from sentry.testutils.silo import assume_test_silo_mode |
10 | 13 |
|
11 | 14 |
|
12 | 15 | class ReleaseDeploysListTest(APITestCase):
|
@@ -389,3 +392,61 @@ def test_environment_validation_failure(self) -> None:
|
389 | 392 | )
|
390 | 393 | assert response.status_code == 400, response.content
|
391 | 394 | assert 0 == Deploy.objects.count()
|
| 395 | + |
| 396 | + def test_api_token_with_project_releases_scope(self): |
| 397 | + """ |
| 398 | + Test that tokens with `project:releases` scope can create deploys for only one project |
| 399 | + when the release is associated with multiple projects. |
| 400 | + """ |
| 401 | + # Create a second project |
| 402 | + project_bar = self.create_project(organization=self.org, name="bar") |
| 403 | + |
| 404 | + # Create a release for both projects |
| 405 | + release = Release.objects.create(organization_id=self.org.id, version="1", total_deploys=0) |
| 406 | + release.add_project(self.project) |
| 407 | + release.add_project(project_bar) |
| 408 | + |
| 409 | + # Create API token with project:releases scope |
| 410 | + user = self.create_user(is_staff=False, is_superuser=False) |
| 411 | + |
| 412 | + # Add user to the organization - they need to be a member to use the API |
| 413 | + self.create_member(user=user, organization=self.org) |
| 414 | + |
| 415 | + with assume_test_silo_mode(SiloMode.CONTROL): |
| 416 | + api_token = ApiToken.objects.create(user=user, scope_list=["project:releases"]) |
| 417 | + |
| 418 | + url = reverse( |
| 419 | + "sentry-api-0-organization-release-deploys", |
| 420 | + kwargs={ |
| 421 | + "organization_id_or_slug": self.org.slug, |
| 422 | + "version": release.version, |
| 423 | + }, |
| 424 | + ) |
| 425 | + |
| 426 | + # Create deploy for only one project (project_bar) |
| 427 | + response = self.client.post( |
| 428 | + url, |
| 429 | + data={ |
| 430 | + "name": "single_project_deploy", |
| 431 | + "environment": "production", |
| 432 | + "url": "https://www.example.com", |
| 433 | + "projects": [project_bar.slug], # Only one project specified |
| 434 | + }, |
| 435 | + HTTP_AUTHORIZATION=f"Bearer {api_token.token}", |
| 436 | + ) |
| 437 | + |
| 438 | + assert response.status_code == 201, response.content |
| 439 | + assert response.data["name"] == "single_project_deploy" |
| 440 | + assert response.data["environment"] == "production" |
| 441 | + |
| 442 | + environment = Environment.objects.get(name="production", organization_id=self.org.id) |
| 443 | + |
| 444 | + # Verify ReleaseProjectEnvironment was created only for project_bar |
| 445 | + assert ReleaseProjectEnvironment.objects.filter( |
| 446 | + project=project_bar, release=release, environment=environment |
| 447 | + ).exists() |
| 448 | + |
| 449 | + # Verify ReleaseProjectEnvironment was NOT created for self.project |
| 450 | + assert not ReleaseProjectEnvironment.objects.filter( |
| 451 | + project=self.project, release=release, environment=environment |
| 452 | + ).exists() |
0 commit comments