fix(backend): move RLS initialization before app_admin role assignment
Reorganize SeedDataService to establish RLS policies before granting app_admin role to prevent permission issues. Remove --no-restore flag from Dockerfile.dev to ensure proper build. Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -28,4 +28,4 @@ COPY . .
|
||||
EXPOSE 8080
|
||||
|
||||
# Hot reload: dotnet watch monitors file changes in mounted volumes
|
||||
ENTRYPOINT ["dotnet", "watch", "run", "--project", "WorkClub.Api/WorkClub.Api.csproj", "--no-restore"]
|
||||
ENTRYPOINT ["dotnet", "watch", "run", "--project", "WorkClub.Api/WorkClub.Api.csproj"]
|
||||
|
||||
@@ -21,6 +21,68 @@ public class SeedDataService
|
||||
{
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
await context.Database.MigrateAsync();
|
||||
|
||||
using var transaction = await context.Database.BeginTransactionAsync();
|
||||
|
||||
// Enable RLS on all tenant tables
|
||||
await context.Database.ExecuteSqlRawAsync(@"
|
||||
ALTER TABLE clubs ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE clubs FORCE ROW LEVEL SECURITY;
|
||||
ALTER TABLE members ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE members FORCE ROW LEVEL SECURITY;
|
||||
ALTER TABLE work_items ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE work_items FORCE ROW LEVEL SECURITY;
|
||||
ALTER TABLE shifts ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE shifts FORCE ROW LEVEL SECURITY;
|
||||
ALTER TABLE shift_signups ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE shift_signups FORCE ROW LEVEL SECURITY;
|
||||
");
|
||||
|
||||
// Create tenant isolation policies (idempotent)
|
||||
await context.Database.ExecuteSqlRawAsync(@"
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='clubs' AND policyname='tenant_isolation_policy') THEN
|
||||
CREATE POLICY tenant_isolation_policy ON clubs FOR ALL USING ((""TenantId"")::text = current_setting('app.current_tenant_id', true));
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='members' AND policyname='tenant_isolation_policy') THEN
|
||||
CREATE POLICY tenant_isolation_policy ON members FOR ALL USING ((""TenantId"")::text = current_setting('app.current_tenant_id', true));
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='work_items' AND policyname='tenant_isolation_policy') THEN
|
||||
CREATE POLICY tenant_isolation_policy ON work_items FOR ALL USING ((""TenantId"")::text = current_setting('app.current_tenant_id', true));
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='shifts' AND policyname='tenant_isolation_policy') THEN
|
||||
CREATE POLICY tenant_isolation_policy ON shifts FOR ALL USING ((""TenantId"")::text = current_setting('app.current_tenant_id', true));
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='shift_signups' AND policyname='tenant_isolation_policy') THEN
|
||||
CREATE POLICY tenant_isolation_policy ON shift_signups FOR ALL USING (""ShiftId"" IN (SELECT ""Id"" FROM shifts WHERE (""TenantId"")::text = current_setting('app.current_tenant_id', true)));
|
||||
END IF;
|
||||
END $$;
|
||||
");
|
||||
|
||||
// Create admin bypass policies (idempotent)
|
||||
await context.Database.ExecuteSqlRawAsync(@"
|
||||
DO $$ BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='clubs' AND policyname='bypass_rls_policy') THEN
|
||||
CREATE POLICY bypass_rls_policy ON clubs FOR ALL TO app_admin USING (true);
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='members' AND policyname='bypass_rls_policy') THEN
|
||||
CREATE POLICY bypass_rls_policy ON members FOR ALL TO app_admin USING (true);
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='work_items' AND policyname='bypass_rls_policy') THEN
|
||||
CREATE POLICY bypass_rls_policy ON work_items FOR ALL TO app_admin USING (true);
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='shifts' AND policyname='bypass_rls_policy') THEN
|
||||
CREATE POLICY bypass_rls_policy ON shifts FOR ALL TO app_admin USING (true);
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE tablename='shift_signups' AND policyname='bypass_rls_policy') THEN
|
||||
CREATE POLICY bypass_rls_policy ON shift_signups FOR ALL TO app_admin USING (true);
|
||||
END IF;
|
||||
END $$;
|
||||
");
|
||||
|
||||
await context.Database.ExecuteSqlRawAsync("SET LOCAL ROLE app_admin");
|
||||
|
||||
// Seed clubs
|
||||
if (!context.Clubs.Any())
|
||||
@@ -437,6 +499,9 @@ public class SeedDataService
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
await context.Database.ExecuteSqlRawAsync("RESET ROLE");
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
|
||||
private static string GenerateDeterministicGuid(string input)
|
||||
|
||||
Reference in New Issue
Block a user