1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2025-12-12 20:54:04 +00:00

Add test for $forceRls = false, refactor BYPASSRLS test

This commit is contained in:
lukinovec 2025-02-05 10:08:55 +01:00
parent 3fabdf8f33
commit d531c972b6

View file

@ -541,33 +541,67 @@ test('table rls manager generates relationship trees with tables related to the
]);
})->with([true, false]);
test('table owner sees all the records when forceRls is false while other users only see records scoped to them', function() {
CreateUserWithRLSPolicies::$forceRls = false;
// Drop all tables created in beforeEach
DB::statement("DROP TABLE authors, categories, posts, comments, reactions, articles;");
[$username, $password] = createPostgresUser('central_user');
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, $tenant2] = [Tenant::create(), Tenant::create()];
pest()->artisan('tenants:rls');
[$order1, $order2] = [
Order::create(['name' => 'order1', 'tenant_id' => $tenant1->getTenantKey()]),
Order::create(['name' => 'order2', 'tenant_id' => $tenant2->getTenantKey()]),
];
// The table owner should see all the records
expect(Order::all())->toHaveCount(2);
tenancy()->initialize($tenant1);
// The tenant users should only see their records
expect(Order::count())->toBe(1);
expect(Order::first()->name)->toBe($order1->name);
tenancy()->initialize($tenant2);
expect(Order::count())->toBe(1);
expect(Order::first()->name)->toBe($order2->name);
});
// https://github.com/tenancy-for-laravel/v4/issues/63
test('user without BYPASSRLS can only query owned tables if forceRls is true', function(bool $forceRls) {
CreateUserWithRLSPolicies::$forceRls = $forceRls;
// Drop all tables created in beforeEach
DB::statement("DROP TABLE authors, categories, posts, comments, reactions, articles;");
try {
DB::statement("DROP OWNED BY administrator;");
} catch (\Throwable $th) {}
DB::statement("DROP USER IF EXISTS administrator;");
// Create new central user (without superuser and bypassrls privileges)
DB::statement("CREATE USER administrator WITH ENCRYPTED PASSWORD 'password'");
DB::statement("ALTER USER administrator CREATEDB");
DB::statement("ALTER USER administrator CREATEROLE");
// Grant privileges to the new central user
DB::statement("GRANT ALL PRIVILEGES ON DATABASE main to administrator");
DB::statement("GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO administrator");
DB::statement("GRANT ALL ON SCHEMA public TO administrator");
DB::statement("ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TABLES TO administrator");
DB::statement("GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO administrator");
[$username, $password] = createPostgresUser('administrator');
config(['database.connections.central' => array_merge(
config('database.connections.pgsql'),
['username' => 'administrator', 'password' => 'password']
['username' => $username, 'password' => $password]
)]);
DB::reconnect();
@ -583,21 +617,11 @@ test('user without BYPASSRLS can only query owned tables if forceRls is true', f
});
$tenant1 = Tenant::create();
$tenant2 = Tenant::create();
// Create RLS policy for the orders table
pest()->artisan('tenants:rls');
tenancy()->initialize($tenant1);
Order::create(['name' => 'order1', 'tenant_id' => $tenant1->getTenantKey()]);
expect(Order::first())->not()->toBeNull();
tenancy()->initialize($tenant2);
expect(Order::first())->toBeNull(); // RLS works
tenancy()->end();
if ($forceRls) {
// RLS is forced, so by default, not even the table owner should be able to query the table protected by the RLS policy.
@ -725,6 +749,28 @@ test('table manager throws an exception when encountering a recursive relationsh
expect(fn () => app(TableRLSManager::class)->generateTrees())->toThrow(RecursiveRelationshipException::class);
});
function createPostgresUser(string $username, string $password = 'password'): array
{
try {
DB::statement("DROP OWNED BY {$username};");
} catch (\Throwable $th) {}
DB::statement("DROP USER IF EXISTS {$username};");
DB::statement("CREATE USER {$username} WITH ENCRYPTED PASSWORD '{$password}'");
DB::statement("ALTER USER {$username} CREATEDB");
DB::statement("ALTER USER {$username} CREATEROLE");
// Grant privileges to the new central user
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 ON SCHEMA public TO {$username}");
DB::statement("ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TABLES TO {$username}");
DB::statement("GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO {$username}");
return [$username, $password];
}
class Post extends Model
{
protected $guarded = [];