Skip to content

Commit d507da5

Browse files
fix(api): check org membership in updateBundleCacheConfig mutation (#919)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 9164119 commit d507da5

4 files changed

Lines changed: 46 additions & 8 deletions

File tree

apps/codecov-api/core/commands/repository/interactors/tests/test_update_bundle_cache_config.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from asgiref.sync import async_to_sync
33
from django.test import TestCase
44

5-
from codecov.commands.exceptions import ValidationError
5+
from codecov.commands.exceptions import Unauthorized, ValidationError
66
from shared.django_apps.bundle_analysis.models import CacheConfig
77
from shared.django_apps.core.tests.factories import (
88
OwnerFactory,
@@ -17,8 +17,12 @@ class UpdateBundleCacheConfigInteractorTest(TestCase):
1717

1818
def setUp(self):
1919
self.org = OwnerFactory(username="test-org")
20-
self.repo = RepositoryFactory(author=self.org, name="test-repo", active=True)
21-
self.user = OwnerFactory(permission=[self.repo.pk])
20+
self.repo = RepositoryFactory(
21+
author=self.org, name="test-repo", active=True, private=False
22+
)
23+
self.user = OwnerFactory(
24+
organizations=[self.org.ownerid], permission=[self.repo.pk]
25+
)
2226

2327
@async_to_sync
2428
def execute(self, owner, repo_name=None, cache_config=[]):
@@ -28,6 +32,15 @@ def execute(self, owner, repo_name=None, cache_config=[]):
2832
cache_config=cache_config,
2933
)
3034

35+
def test_unauthorized_user_not_part_of_org(self):
36+
random_user = OwnerFactory()
37+
with pytest.raises(Unauthorized):
38+
self.execute(
39+
owner=random_user,
40+
repo_name="test-repo",
41+
cache_config=[{"bundle_name": "any", "toggle_caching": False}],
42+
)
43+
3144
def test_repo_not_found(self):
3245
with pytest.raises(ValidationError):
3346
self.execute(owner=self.user, repo_name="wrong")

apps/codecov-api/core/commands/repository/interactors/update_bundle_cache_config.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from asgiref.sync import sync_to_async
22

33
from codecov.commands.base import BaseInteractor
4-
from codecov.commands.exceptions import ValidationError
4+
from codecov.commands.exceptions import Unauthorized, ValidationError
5+
from codecov_auth.helpers import current_user_part_of_org
56
from core.models import Repository
67
from shared.django_apps.bundle_analysis.models import CacheConfig
78
from shared.django_apps.bundle_analysis.service.bundle_analysis import (
@@ -38,10 +39,13 @@ def execute(
3839
repo_name: str,
3940
cache_config: list[dict[str, str | bool]],
4041
) -> list[dict[str, str | bool]]:
41-
_owner, repo = self.resolve_owner_and_repo(
42+
owner, repo = self.resolve_owner_and_repo(
4243
owner_username, repo_name, only_viewable=True
4344
)
4445

46+
if not current_user_part_of_org(self.current_owner, owner):
47+
raise Unauthorized()
48+
4549
self.validate(repo, cache_config)
4650

4751
results = []

apps/codecov-api/graphql_api/tests/mutation/test_update_bundle_cache_config.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from django.test import TestCase
44

55
from graphql_api.tests.helper import GraphQLTestHelper
6-
from shared.django_apps.core.tests.factories import OwnerFactory
6+
from shared.django_apps.core.tests.factories import OwnerFactory, RepositoryFactory
77

88
query = """
99
mutation($input: ActivateMeasurementsInput!) {
@@ -37,6 +37,9 @@
3737
... on UnauthenticatedError {
3838
message
3939
}
40+
... on UnauthorizedError {
41+
message
42+
}
4043
... on ValidationError {
4144
message
4245
}
@@ -48,7 +51,9 @@
4851

4952
class UpdateBundleCacheConfigTestCase(GraphQLTestHelper, TestCase):
5053
def setUp(self):
51-
self.owner = OwnerFactory()
54+
self.org = OwnerFactory(username="codecov")
55+
self.repo = RepositoryFactory(author=self.org, name="test-repo", private=False)
56+
self.owner = OwnerFactory(organizations=[self.org.ownerid])
5257

5358
def test_when_unauthenticated(self):
5459
data = self.gql_request(
@@ -64,6 +69,22 @@ def test_when_unauthenticated(self):
6469
== "UnauthenticatedError"
6570
)
6671

72+
def test_when_unauthorized_user_not_part_of_org(self):
73+
random_user = OwnerFactory()
74+
data = self.gql_request(
75+
query,
76+
owner=random_user,
77+
variables={
78+
"owner": "codecov",
79+
"repoName": "test-repo",
80+
"bundles": [{"bundleName": "pr_bundle1", "toggleCaching": False}],
81+
},
82+
)
83+
assert (
84+
data["updateBundleCacheConfig"]["error"]["__typename"]
85+
== "UnauthorizedError"
86+
)
87+
6788
@patch(
6889
"core.commands.repository.interactors.update_bundle_cache_config.UpdateBundleCacheConfigInteractor.execute"
6990
)

apps/codecov-api/graphql_api/types/mutation/update_bundle_cache_config/update_bundle_cache_config.graphql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
union UpdateBundleCacheConfigError = UnauthenticatedError | ValidationError
1+
union UpdateBundleCacheConfigError = UnauthenticatedError | UnauthorizedError | ValidationError
22

33
type UpdateBundleCacheConfigResult {
44
bundleName: String

0 commit comments

Comments
 (0)