tenant1Id = DB::table('tenants')->insertGetId([ 'subdomain' => 'rls-tenant-a-'.uniqid(), 'organization_name' => 'RLS Tenant A', 'contact_email' => 'a@rls-test.local', 'webhook_token' => 'whtA'.str_pad((string) random_int(0, 999999999), 60, '0', STR_PAD_LEFT), 'api_key_limit' => 5, ]); $this->tenant2Id = DB::table('tenants')->insertGetId([ 'subdomain' => 'rls-tenant-b-'.uniqid(), 'organization_name' => 'RLS Tenant B', 'contact_email' => 'b@rls-test.local', 'webhook_token' => 'whtB'.str_pad((string) random_int(0, 999999999), 60, '0', STR_PAD_LEFT), 'api_key_limit' => 5, ]); $this->project1Id = DB::table('projects')->insertGetId([ 'tenant_id' => $this->tenant1Id, 'name' => 'Project A1', ]); $this->project2Id = DB::table('projects')->insertGetId([ 'tenant_id' => $this->tenant2Id, 'name' => 'Project B1', ]); DB::table('deals')->insert([ ['tenant_id' => $this->tenant1Id, 'project_id' => $this->project1Id, 'phone' => '+79000010001', 'received_at' => now()], ['tenant_id' => $this->tenant1Id, 'project_id' => $this->project1Id, 'phone' => '+79000010002', 'received_at' => now()], ['tenant_id' => $this->tenant2Id, 'project_id' => $this->project2Id, 'phone' => '+79000020001', 'received_at' => now()], ['tenant_id' => $this->tenant2Id, 'project_id' => $this->project2Id, 'phone' => '+79000020002', 'received_at' => now()], ]); }); test('кейс 1: SET LOCAL app.current_tenant_id изолирует SELECT в deals', function () { DB::statement('SET LOCAL ROLE testing_rls_user'); DB::statement("SET LOCAL app.current_tenant_id = '{$this->tenant1Id}'"); $allDealsVisible = DB::table('deals')->count(); $foreignDealsVisible = DB::table('deals')->where('tenant_id', $this->tenant2Id)->count(); expect($allDealsVisible)->toBe(2); expect($foreignDealsVisible)->toBe(0); }); test('кейс 1: переключение tenant_id показывает только свои deals', function () { DB::statement('SET LOCAL ROLE testing_rls_user'); DB::statement("SET LOCAL app.current_tenant_id = '{$this->tenant2Id}'"); $allDealsVisible = DB::table('deals')->count(); $foreignDealsVisible = DB::table('deals')->where('tenant_id', $this->tenant1Id)->count(); expect($allDealsVisible)->toBe(2); expect($foreignDealsVisible)->toBe(0); }); test('кейс 1: RLS работает на projects и users (не только deals)', function () { DB::statement('SET LOCAL ROLE testing_rls_user'); DB::statement("SET LOCAL app.current_tenant_id = '{$this->tenant1Id}'"); $projectsVisible = DB::table('projects')->count(); $foreignProjectsVisible = DB::table('projects')->where('tenant_id', $this->tenant2Id)->count(); expect($projectsVisible)->toBe(1); expect($foreignProjectsVisible)->toBe(0); }); test('кейс 4: WITH CHECK блокирует INSERT projects с чужим tenant_id', function () { DB::statement('SET LOCAL ROLE testing_rls_user'); DB::statement("SET LOCAL app.current_tenant_id = '{$this->tenant1Id}'"); expect(fn () => DB::table('projects')->insert([ 'tenant_id' => $this->tenant2Id, 'name' => 'Hijack attempt', ]))->toThrow(QueryException::class); });