114 lines
5.1 KiB
PHP
114 lines
5.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Feature\Api\Admin;
|
|
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Spatie\Permission\Models\Permission;
|
|
use Spatie\Permission\Models\Role;
|
|
use Tests\TestCase;
|
|
|
|
class PermissionGatingTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
// CheckPermission throws when the checked permission row doesn't exist at all —
|
|
// seed every permission this test touches so unauthorized checks 403 instead of 500.
|
|
foreach (self::gatedRoutesProvider() as [, , $permission]) {
|
|
Permission::firstOrCreate(['name' => $permission, 'guard_name' => 'admin']);
|
|
}
|
|
Permission::firstOrCreate(['name' => 'some-other.manager', 'guard_name' => 'admin']);
|
|
}
|
|
|
|
private function makeAdminWithPermissions(array $permissions): User
|
|
{
|
|
$role = Role::create(['name' => 'role-' . uniqid(), 'guard_name' => 'admin']);
|
|
foreach ($permissions as $permission) {
|
|
$role->givePermissionTo(
|
|
Permission::firstOrCreate(['name' => $permission, 'guard_name' => 'admin']),
|
|
);
|
|
}
|
|
|
|
$admin = User::factory()->create();
|
|
$admin->assignRole($role);
|
|
|
|
return $admin;
|
|
}
|
|
|
|
/** @dataProvider gatedRoutesProvider */
|
|
public function test_route_requires_expected_permission(string $method, string $uri, string $requiredPermission): void
|
|
{
|
|
$unauthorized = $this->makeAdminWithPermissions(['some-other.manager']);
|
|
$this->actingAs($unauthorized, 'admin')->json($method, $uri)->assertStatus(403);
|
|
|
|
$authorized = $this->makeAdminWithPermissions([$requiredPermission]);
|
|
$response = $this->actingAs($authorized, 'admin')->json($method, $uri);
|
|
$this->assertNotSame(403, $response->status(), "Expected {$uri} to be accessible with '{$requiredPermission}', got 403.");
|
|
}
|
|
|
|
public static function gatedRoutesProvider(): array
|
|
{
|
|
return [
|
|
'settings index' => ['GET', '/api/v1/administrator/settings', 'setting.manager'],
|
|
'banks index' => ['GET', '/api/v1/administrator/banks', 'setting.manager'],
|
|
'domain-pricing index' => ['GET', '/api/v1/administrator/domain-pricing', 'setting.manager'],
|
|
'email-templates index' => ['GET', '/api/v1/administrator/email-templates', 'email-template.manager'],
|
|
'tickets index' => ['GET', '/api/v1/administrator/tickets', 'support.view'],
|
|
'activity-logs index' => ['GET', '/api/v1/administrator/activity-logs', 'system-log.manager'],
|
|
'email-logs index' => ['GET', '/api/v1/administrator/email-logs', 'system-log.manager'],
|
|
'post-categories index' => ['GET', '/api/v1/administrator/post-categories', 'post.view'],
|
|
'posts index' => ['GET', '/api/v1/administrator/posts', 'post.view'],
|
|
'media index' => ['GET', '/api/v1/administrator/media', 'media.view'],
|
|
'dashboard stats' => ['GET', '/api/v1/administrator/dashboard/stats', 'dashboard.view'],
|
|
'queue jobs recent' => ['GET', '/api/v1/administrator/queue/jobs/recent', 'queue.manager'],
|
|
];
|
|
}
|
|
|
|
public function test_force_delete_post_requires_post_destroy_permission(): void
|
|
{
|
|
Permission::firstOrCreate(['name' => 'post.destroy', 'guard_name' => 'admin']);
|
|
|
|
$unauthorized = $this->makeAdminWithPermissions(['post.view']);
|
|
$this->actingAs($unauthorized, 'admin')
|
|
->deleteJson('/api/v1/administrator/posts/999/force-delete')
|
|
->assertStatus(403);
|
|
|
|
$authorized = $this->makeAdminWithPermissions(['post.destroy']);
|
|
$response = $this->actingAs($authorized, 'admin')
|
|
->deleteJson('/api/v1/administrator/posts/999/force-delete');
|
|
$this->assertNotSame(403, $response->status());
|
|
}
|
|
|
|
public function test_dashboard_requires_dashboard_view_permission(): void
|
|
{
|
|
Permission::firstOrCreate(['name' => 'dashboard.view', 'guard_name' => 'admin']);
|
|
|
|
$unauthorized = $this->makeAdminWithPermissions(['post.view']);
|
|
$this->actingAs($unauthorized, 'admin')
|
|
->getJson('/api/v1/administrator/dashboard/stats')
|
|
->assertStatus(403);
|
|
|
|
$authorized = $this->makeAdminWithPermissions(['dashboard.view']);
|
|
$response = $this->actingAs($authorized, 'admin')->getJson('/api/v1/administrator/dashboard/stats');
|
|
$this->assertNotSame(403, $response->status());
|
|
}
|
|
|
|
public function test_full_administrator_bypasses_all_permission_gates(): void
|
|
{
|
|
Role::firstOrCreate(['name' => 'Full Administrator', 'guard_name' => 'admin']);
|
|
$admin = User::factory()->create();
|
|
$admin->assignRole('Full Administrator');
|
|
|
|
foreach (self::gatedRoutesProvider() as [$method, $uri]) {
|
|
$response = $this->actingAs($admin, 'admin')->json($method, $uri);
|
|
$this->assertNotSame(403, $response->status(), "Full Administrator should not be blocked from {$uri}.");
|
|
}
|
|
}
|
|
}
|