artisan('lottery:admin-auth-sync')->assertExitCode(0); }); function platformRolesApiToken(string $username): string { $admin = AdminUser::query()->create([ 'username' => $username, 'name' => 'Tester', 'email' => null, 'password' => Hash::make('secret-strong'), 'status' => 0, ]); grantSuperAdminRole($admin); return $admin->createToken('test', ['*'], now()->addDay())->plainTextToken; } test('platform role index lists built-in roles and custom system roles', function (): void { AdminRole::query()->create([ 'slug' => 'legacy_custom_ops', 'code' => 'legacy_custom_ops', 'name' => 'Legacy Ops', 'scope_type' => AdminRole::SCOPE_SYSTEM, 'status' => 1, 'is_system' => false, 'sort_order' => 99, ]); PlatformSystemRoles::ensureAll(); $token = platformRolesApiToken('platform_role_index'); $slugs = collect($this->withHeader('Authorization', 'Bearer '.$token) ->getJson('/api/v1/admin/admin-roles') ->assertOk() ->json('data.items')) ->pluck('slug') ->all(); expect($slugs)->toContain('super_admin', 'site_admin', 'agent', 'legacy_custom_ops'); }); test('admin can create custom platform role but not reserved slugs', function (): void { PlatformSystemRoles::ensureAll(); $token = platformRolesApiToken('platform_role_create'); $this->withHeader('Authorization', 'Bearer '.$token) ->postJson('/api/v1/admin/admin-roles', [ 'slug' => 'super_admin', 'name' => 'Fake Super', ]) ->assertStatus(422); $this->withHeader('Authorization', 'Bearer '.$token) ->postJson('/api/v1/admin/admin-roles', [ 'slug' => 'new_ops', 'name' => 'New Ops', 'description' => 'Custom ops role', 'permission_slugs' => ['prd.dashboard.view'], ]) ->assertCreated() ->assertJsonPath('data.slug', 'new_ops') ->assertJsonPath('data.name', 'New Ops') ->assertJsonPath('data.is_system', false); expect(AdminRole::query()->where('slug', 'new_ops')->exists())->toBeTrue(); }); test('super_admin built-in role remains protected', function (): void { PlatformSystemRoles::ensureAll(); $token = platformRolesApiToken('platform_role_guard'); $menuActionCount = (int) DB::table('admin_menu_actions')->where('status', 1)->count(); $super = AdminRole::query()->where('slug', 'super_admin')->firstOrFail(); expect($super->is_system)->toBeTrue(); expect((int) DB::table('admin_role_menu_actions')->where('role_id', $super->id)->count()) ->toBe($menuActionCount); expect($super->legacyPermissionSlugs())->not->toBeEmpty(); $this->withHeader('Authorization', 'Bearer '.$token) ->putJson('/api/v1/admin/admin-roles/'.$super->id.'/permissions', [ 'permission_slugs' => ['prd.dashboard.view'], ]) ->assertStatus(422); $this->withHeader('Authorization', 'Bearer '.$token) ->putJson('/api/v1/admin/admin-roles/'.$super->id, [ 'name' => 'Renamed Super', ]) ->assertStatus(422); $this->withHeader('Authorization', 'Bearer '.$token) ->deleteJson('/api/v1/admin/admin-roles/'.$super->id) ->assertStatus(422); }); test('admin-auth-sync grants super_admin the full permission catalog', function (): void { $this->artisan('lottery:admin-auth-sync')->assertExitCode(0); $super = AdminRole::query()->where('slug', 'super_admin')->firstOrFail(); $menuActionCount = (int) DB::table('admin_menu_actions')->where('status', 1)->count(); expect((int) DB::table('admin_role_menu_actions')->where('role_id', $super->id)->count()) ->toBe($menuActionCount); });