1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-02-05 11:44:04 +00:00

Add test that makes the bypassrls/forceRls behavior clear

This commit is contained in:
lukinovec 2025-06-04 13:16:48 +02:00
parent 12786a36db
commit b48826cc33

View file

@ -768,7 +768,59 @@ test('table manager ignores recursive relationship if the foreign key responsibl
expect(fn () => app(TableRLSManager::class)->generateTrees())->not()->toThrow(RecursiveRelationshipException::class); expect(fn () => app(TableRLSManager::class)->generateTrees())->not()->toThrow(RecursiveRelationshipException::class);
}); });
function createPostgresUser(string $username, string $password = 'password'): array test('users with BYPASSRLS privilege can bypass RLS regardless of forceRls setting', function(bool $forceRls, bool $bypassRls) {
CreateUserWithRLSPolicies::$forceRls = $forceRls;
// Drop all tables created in beforeEach
DB::statement("DROP TABLE authors, categories, posts, comments, reactions, articles;");
[$username, $password] = createPostgresUser('administrator', 'password', $bypassRls);
config(['database.connections.central' => array_merge(
config('database.connections.pgsql'),
['username' => $username, 'password' => $password]
)]);
DB::reconnect();
Schema::create('orders', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('tenant_id')->comment('rls');
$table->foreign('tenant_id')->references('id')->on('tenants')->onUpdate('cascade')->onDelete('cascade');
$table->timestamps();
});
$tenant1 = Tenant::create();
// Create RLS policy for the orders table
pest()->artisan('tenants:rls');
$tenant1->run(fn () => Order::create(['name' => 'order1', 'tenant_id' => $tenant1->getTenantKey()]));
if ($bypassRls) {
// Users with BYPASSRLS can always query tables regardless of forceRls setting
// This is the normal production setup behavior
expect(Order::first())->not()->toBeNull();
expect(Order::first()->name)->toBe('order1');
} else {
// Users without BYPASSRLS are subject to RLS policies even if they're table owners when forceRls is true
// OR they can bypass as table owners (when forceRls=false)
if ($forceRls) {
// Even table owners need session variable
expect(fn () => Order::first())->toThrow(QueryException::class, 'unrecognized configuration parameter');
} else {
// Table owners can bypass RLS automatically
expect(Order::first())->not()->toBeNull();
expect(Order::first()->name)->toBe('order1');
}
}
})->with([true, false])
->with([true, false]);
function createPostgresUser(string $username, string $password = 'password', bool $bypassRls = false): array
{ {
try { try {
DB::statement("DROP OWNED BY {$username};"); DB::statement("DROP OWNED BY {$username};");
@ -780,6 +832,11 @@ function createPostgresUser(string $username, string $password = 'password'): ar
DB::statement("ALTER USER {$username} CREATEDB"); DB::statement("ALTER USER {$username} CREATEDB");
DB::statement("ALTER USER {$username} CREATEROLE"); DB::statement("ALTER USER {$username} CREATEROLE");
// Grant BYPASSRLS privilege if requested
if ($bypassRls) {
DB::statement("ALTER USER {$username} BYPASSRLS");
}
// Grant privileges to the new central user // Grant privileges to the new central user
DB::statement("GRANT ALL PRIVILEGES ON DATABASE main to {$username}"); DB::statement("GRANT ALL PRIVILEGES ON DATABASE main to {$username}");
DB::statement("GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO {$username}"); DB::statement("GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO {$username}");