From 676161a627aab9291837e573b701701db4d141b3 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Tue, 7 Jul 2026 20:56:55 +0200 Subject: [PATCH] fix(api): authorize target environment moves --- bootstrap/helpers/api.php | 3 +++ tests/Feature/MoveResourceApiTest.php | 31 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/bootstrap/helpers/api.php b/bootstrap/helpers/api.php index 54f275991..dccfec4af 100644 --- a/bootstrap/helpers/api.php +++ b/bootstrap/helpers/api.php @@ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Gate; use Illuminate\Validation\Rule; function getTeamIdFromToken() @@ -202,6 +203,8 @@ function moveResourceToEnvironment(Request $request, $resource, string $resource return response()->json(['message' => 'Target environment not found or not owned by your team.'], 404); } + Gate::authorize('update', $newEnvironment); + if ($resource->environment_id === $newEnvironment->id) { return response()->json(['message' => "$resourceType is already in this environment."], 400); } diff --git a/tests/Feature/MoveResourceApiTest.php b/tests/Feature/MoveResourceApiTest.php index faf4f699b..82ee221b1 100644 --- a/tests/Feature/MoveResourceApiTest.php +++ b/tests/Feature/MoveResourceApiTest.php @@ -11,6 +11,7 @@ use App\Models\Team; use App\Models\User; use Illuminate\Foundation\Testing\RefreshDatabase; +use Illuminate\Support\Facades\Gate; uses(RefreshDatabase::class); @@ -123,6 +124,36 @@ $response->assertStatus(404); }); + test('returns 403 when target environment update is denied', function () { + $application = Application::factory()->create([ + 'environment_id' => $this->environment->id, + 'destination_id' => $this->destination->id, + 'destination_type' => $this->destination->getMorphClass(), + ]); + + Gate::before(function (User $user, string $ability, array $arguments) { + $target = $arguments[0] ?? null; + + if ($ability === 'update' && $target instanceof Environment && $target->is($this->targetEnvironment)) { + return false; + } + + return null; + }); + + $response = $this->withHeaders([ + 'Authorization' => 'Bearer '.$this->bearerToken, + 'Content-Type' => 'application/json', + ])->postJson("/api/v1/applications/{$application->uuid}/move", [ + 'environment_uuid' => $this->targetEnvironment->uuid, + ]); + + $response->assertForbidden(); + + $application->refresh(); + expect($application->environment_id)->toBe($this->environment->id); + }); + test('returns 400 when application is already in the target environment', function () { $application = Application::factory()->create([ 'environment_id' => $this->environment->id,