Skip to content
Merged
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 api/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ dependencies = [
"backoff>=2.2.1,<2.3.0",
"appdirs>=1.4.4,<1.5.0",
"django-cors-headers>=3.5.0,<3.6.0",
"djangorestframework>=3.15.2,<3.16.0",
"djangorestframework>=3.17.2,<3.18.0",
"gunicorn>=23.0.0,<23.1.0",
"pyparsing>=2.4.7,<2.5.0",
"requests>=2.33.0,<2.34.0",
Expand Down
38 changes: 38 additions & 0 deletions api/tests/integration/trust_relationships/test_viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,44 @@ def test_create_trust_relationship__duplicate_issuer_and_audience__returns_400(
]


def test_update_trust_relationship__duplicate_issuer_and_audience__returns_400(
admin_client: APIClient,
organisation: int,
trust_relationship: int,
) -> None:
# Given
create_response = admin_client.post(
f"/api/v1/organisations/{organisation}/trust-relationships/",
data={
"name": "GitLab CI",
"issuer": "https://gitlab.com",
"audience": "https://gitlab.com/Flagsmith",
"is_admin": True,
},
format="json",
)
assert create_response.status_code == status.HTTP_201_CREATED
url = (
f"/api/v1/organisations/{organisation}"
f"/trust-relationships/{create_response.json()['id']}/"
)
data = {
"name": "GitLab CI",
"issuer": "https://token.actions.githubusercontent.com",
"audience": "https://github.com/Flagsmith",
"is_admin": True,
}

# When
response = admin_client.put(url, data=data, format="json")

# Then
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.json()["non_field_errors"] == [
"The fields issuer, audience must make a unique set."
]


def test_create_trust_relationship__same_issuer_and_audience_as_deleted__returns_201(
admin_client: APIClient,
organisation: int,
Expand Down
11 changes: 11 additions & 0 deletions api/trust_relationships/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from django.conf import settings
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator

from trust_relationships.models import TrustRelationship
from trust_relationships.services import (
Expand Down Expand Up @@ -62,6 +63,16 @@ class Meta:
"created_by",
)
read_only_fields = ("id", "created_at", "created_by")
# Declared manually — since DRF 3.16 it can't auto-generate a validator
# for `unique_live_issuer_audience`, whose condition is on `deleted_at`,
# a field not writable here. `objects` excludes soft-deleted rows.
# https://github.com/encode/django-rest-framework/discussions/9777
Comment thread
matthewelwell marked this conversation as resolved.
validators = [
UniqueTogetherValidator(
queryset=TrustRelationship.objects.all(),
fields=("issuer", "audience"),
)
]

def validate_issuer(self, issuer: str) -> str:
parsed = urlparse(issuer)
Expand Down
8 changes: 4 additions & 4 deletions api/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25891,6 +25891,7 @@ components:
is_system_tag:
description: 'Indicates that a tag was created by the system, not the user.'
type: boolean
default: false
readOnly: true
type:
description: |-
Expand Down Expand Up @@ -27985,6 +27986,7 @@ components:
is_system_tag:
description: 'Indicates that a tag was created by the system, not the user.'
type: boolean
default: false
readOnly: true
type:
description: |-
Expand Down
Loading