From 5789e87f4f972620405862a3c2fc84cd92520bc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20Poyatos?= Date: Tue, 14 Oct 2025 13:30:41 +0200 Subject: [PATCH] fix(api-keys): update `created` field to never update (#8908) --- .../backend/api/migrations/0048_api_key.py | 2 +- api/src/backend/api/models.py | 1 + api/src/backend/api/tests/test_views.py | 21 +++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/api/src/backend/api/migrations/0048_api_key.py b/api/src/backend/api/migrations/0048_api_key.py index abcbe212ef..32b7fe144d 100644 --- a/api/src/backend/api/migrations/0048_api_key.py +++ b/api/src/backend/api/migrations/0048_api_key.py @@ -44,7 +44,7 @@ class Migration(migrations.Migration): help_text="If the API key is revoked, entities cannot use it anymore. (This cannot be undone.)", ), ), - ("created", models.DateTimeField(auto_now=True)), + ("created", models.DateTimeField(auto_now_add=True, editable=False)), ( "whitelisted_ips", models.JSONField( diff --git a/api/src/backend/api/models.py b/api/src/backend/api/models.py index c3cd30d932..a83bb4c585 100644 --- a/api/src/backend/api/models.py +++ b/api/src/backend/api/models.py @@ -221,6 +221,7 @@ class Membership(models.Model): class TenantAPIKey(AbstractAPIKey, RowLevelSecurityProtectedModel): id = models.UUIDField(primary_key=True, default=uuid4, editable=False) name = models.CharField(max_length=100, validators=[MinLengthValidator(3)]) + created = models.DateTimeField(auto_now_add=True, editable=False) prefix = models.CharField( max_length=11, unique=True, diff --git a/api/src/backend/api/tests/test_views.py b/api/src/backend/api/tests/test_views.py index 11dc1c8b33..1b1783cc5a 100644 --- a/api/src/backend/api/tests/test_views.py +++ b/api/src/backend/api/tests/test_views.py @@ -7948,6 +7948,27 @@ class TestTenantApiKeyViewSet: api_key.refresh_from_db() assert api_key.revoked is True + def test_api_keys_revoke_preserves_created_field( + self, authenticated_client, api_keys_fixture + ): + """Test that revoking an API key preserves the created timestamp.""" + api_key = api_keys_fixture[0] # Not revoked + assert api_key.revoked is False + + # Record the original created timestamp + original_created = api_key.created + + response = authenticated_client.delete( + reverse("api-key-revoke", kwargs={"pk": api_key.id}) + ) + assert response.status_code == status.HTTP_200_OK + + # Verify in database + api_key.refresh_from_db() + assert api_key.revoked is True + # Verify created field has not changed + assert api_key.created == original_created + def test_api_keys_revoke_already_revoked( self, authenticated_client, api_keys_fixture ):