Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ ENV ACCESS_LOG_LOCATION=${ACCESS_LOG_LOCATION} \
DJANGO_SETTINGS_MODULE=app.settings.production \
GUNICORN_WORKERS=3 \
GUNICORN_THREADS=2 \
APPLICATION_LOGGERS="app_analytics,audit,code_references,common,core,dynamodb,edge_api,environments,features,import_export,integrations,mcp,oauth2_metadata,organisations,projects,segment_membership,segments,task_processor,users,webhooks,workflows"
APPLICATION_LOGGERS="app_analytics,audit,code_references,common,core,dynamodb,edge_api,environments,features,import_export,integrations,mcp,oauth2_metadata,organisations,projects,segment_membership,segments,task_processor,trust_relationships,users,webhooks,workflows"

ARG CI_COMMIT_SHA
RUN echo ${CI_COMMIT_SHA} > /app/CI_COMMIT_SHA && \
Expand Down
28 changes: 18 additions & 10 deletions api/api_keys/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from rest_framework import viewsets
from rest_framework.authentication import BaseAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView

from organisations.permissions.permissions import (
NestedIsOrganisationAdminPermission,
Expand All @@ -11,25 +12,32 @@
from .serializers import MasterAPIKeySerializer


class MasterAPIKeyViewSet(viewsets.ModelViewSet): # type: ignore[type-arg]
class ExcludeMasterAPIKeyAuthenticationMixin(APIView):
# Machine credentials must not be able to manage machine credentials.
def get_authenticators(self) -> list[BaseAuthentication]:
return [
authenticator
for authenticator in super().get_authenticators()
if not isinstance(authenticator, MasterAPIKeyAuthentication)
]


class MasterAPIKeyViewSet(
ExcludeMasterAPIKeyAuthenticationMixin,
viewsets.ModelViewSet, # type: ignore[type-arg]
):
lookup_field = "prefix"
serializer_class = MasterAPIKeySerializer

permission_classes = [IsAuthenticated, NestedIsOrganisationAdminPermission]

def get_queryset(self): # type: ignore[no-untyped-def]
return MasterAPIKey.objects.filter(
organisation_id=self.kwargs.get("organisation_pk"), revoked=False
organisation_id=self.kwargs.get("organisation_pk"),
revoked=False,
trust_relationship__isnull=True,
)

def get_authenticators(self) -> list[BaseAuthentication]:
# API Keys should not be able to create API Keys
return [
authenticator
for authenticator in super().get_authenticators()
if not isinstance(authenticator, MasterAPIKeyAuthentication)
]

def perform_create(self, serializer): # type: ignore[no-untyped-def]
serializer.save(
organisation_id=self.kwargs.get("organisation_pk"),
Expand Down
1 change: 1 addition & 0 deletions api/app/settings/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
"projects.code_references",
"projects.tags",
"api_keys",
"trust_relationships",
"webhooks",
"metrics",
"onboarding",
Expand Down
2 changes: 1 addition & 1 deletion api/organisations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class OrganisationRole(models.TextChoices):
USER = ("USER", "User")


class Organisation(LifecycleModelMixin, SoftDeleteExportableModel): # type: ignore[misc]
class Organisation(LifecycleModelMixin, SoftDeleteExportableModel): # type: ignore[django-manager-missing,misc]
name = models.CharField(max_length=2000)
has_requested_features = models.BooleanField(default=False)
webhook_notification_email = models.EmailField(null=True, blank=True)
Expand Down
6 changes: 6 additions & 0 deletions api/organisations/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
OrganisationAPIUsageNotificationView,
OrganisationWebhookViewSet,
)
from trust_relationships.views import TrustRelationshipViewSet
from users.views import (
FFAdminUserViewSet,
UserPermissionGroupViewSet,
Expand Down Expand Up @@ -64,6 +65,11 @@
organisations_router.register(
r"master-api-keys", MasterAPIKeyViewSet, basename="organisation-master-api-keys"
)
organisations_router.register(
r"trust-relationships",
TrustRelationshipViewSet,
basename="organisation-trust-relationships",
)
organisations_router.register(
"user-permissions",
UserOrganisationPermissionViewSet,
Expand Down
Empty file.
22 changes: 22 additions & 0 deletions api/tests/integration/trust_relationships/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import pytest
from rest_framework import status
from rest_framework.test import APIClient


@pytest.fixture()
def trust_relationship(
admin_client: APIClient,
organisation: int,
) -> int:
response = admin_client.post(
f"/api/v1/organisations/{organisation}/trust-relationships/",
data={
"name": "GitHub Actions",
"issuer": "https://token.actions.githubusercontent.com",
"audience": "https://github.com/Flagsmith",
"claim_rules": [{"claim": "repository", "values": ["Flagsmith/flagsmith"]}],
},
format="json",
)
assert response.status_code == status.HTTP_201_CREATED
return response.json()["id"] # type: ignore[no-any-return]
Loading
Loading