From a26f5af2daaa8ecebb658a7573cccffabe122a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Fri, 15 May 2026 22:06:14 +0300 Subject: [PATCH] refactor(api): ApiKeyController index() excludes expired keys (review M1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code-quality review of Task 3: index() filtered by is_active only — an expired-but-active key would be listed as valid. Adds an expires_at > now() filter plus a test. Cannot occur today (regenerate is the only write path, always +1 year) but is the correct semantic contract for an «active key» listing. phpstan-baseline.neon: count bumps only for ApiKeyControllerTest.php ($tenant 5→7, $user 3→5, getJson 3→4). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Http/Controllers/Api/ApiKeyController.php | 1 + app/phpstan-baseline.neon | 6 +++--- app/tests/Feature/ApiKeyControllerTest.php | 20 +++++++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/app/app/Http/Controllers/Api/ApiKeyController.php b/app/app/Http/Controllers/Api/ApiKeyController.php index 18f24f21..644492cf 100644 --- a/app/app/Http/Controllers/Api/ApiKeyController.php +++ b/app/app/Http/Controllers/Api/ApiKeyController.php @@ -31,6 +31,7 @@ class ApiKeyController extends Controller $keys = ApiKey::query() ->where('tenant_id', $tenantId) ->where('is_active', true) + ->where('expires_at', '>', now()) ->orderByDesc('created_at') ->get(['id', 'name', 'key_prefix', 'last_used_at', 'expires_at', 'created_at']); diff --git a/app/phpstan-baseline.neon b/app/phpstan-baseline.neon index 414dbc69..bacbacb1 100644 --- a/app/phpstan-baseline.neon +++ b/app/phpstan-baseline.neon @@ -243,13 +243,13 @@ parameters: - message: '#^Access to an undefined property Pest\\PendingCalls\\TestCall\:\:\$tenant\.$#' identifier: property.notFound - count: 5 + count: 7 path: tests/Feature/ApiKeyControllerTest.php - message: '#^Access to an undefined property Pest\\PendingCalls\\TestCall\:\:\$user\.$#' identifier: property.notFound - count: 3 + count: 5 path: tests/Feature/ApiKeyControllerTest.php - @@ -261,7 +261,7 @@ parameters: - message: '#^Call to an undefined method Pest\\PendingCalls\\TestCall\:\:getJson\(\)\.$#' identifier: method.notFound - count: 3 + count: 4 path: tests/Feature/ApiKeyControllerTest.php - diff --git a/app/tests/Feature/ApiKeyControllerTest.php b/app/tests/Feature/ApiKeyControllerTest.php index c6465b6d..5a90ec95 100644 --- a/app/tests/Feature/ApiKeyControllerTest.php +++ b/app/tests/Feature/ApiKeyControllerTest.php @@ -43,6 +43,26 @@ test('GET /api/api-keys изолирован по тенанту', function () { expect($response->json('data'))->toHaveCount(0); }); +test('GET /api/api-keys не возвращает истёкшие ключи', function () { + ApiKey::factory()->create([ + 'tenant_id' => $this->tenant->id, + 'user_id' => $this->user->id, + 'is_active' => true, + 'expires_at' => now()->subDay(), + ]); + ApiKey::factory()->create([ + 'tenant_id' => $this->tenant->id, + 'user_id' => $this->user->id, + 'is_active' => true, + 'expires_at' => now()->addYear(), + ]); + + $response = $this->getJson('/api/api-keys'); + + $response->assertOk(); + expect($response->json('data'))->toHaveCount(1); +}); + test('POST /api/api-keys/regenerate создаёт ключ и возвращает plaintext один раз', function () { $response = $this->postJson('/api/api-keys/regenerate');