fix(api): add FOR UPDATE lock to super user claim transaction
CRITICAL race condition: two concurrent POST /api/setup requests could both
read "no super user exists" before either acquired a lock, allowing two
super users to be created.
Added .for("update") to the staff SELECT query inside the transaction.
PostgreSQL FOR UPDATE serializes concurrent claims — the second transaction
blocks on the lock until the first commits, then sees the existing super user
and returns 409.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
committed by
Flea Flicker
parent
30b49e82e8
commit
1e417eccb1
@@ -38,11 +38,13 @@ setupRouter.post("/", zValidator("json", setupSchema), async (c) => {
|
|||||||
.from(businessSettings)
|
.from(businessSettings)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
// Check if any super user already exists (race condition guard)
|
// Lock super user rows to prevent concurrent claims
|
||||||
|
// FOR UPDATE serializes concurrent claims: second transaction blocks until first commits
|
||||||
const [existingSuperUser] = await tx
|
const [existingSuperUser] = await tx
|
||||||
.select({ id: staff.id })
|
.select({ id: staff.id })
|
||||||
.from(staff)
|
.from(staff)
|
||||||
.where(eq(staff.isSuperUser, true))
|
.where(eq(staff.isSuperUser, true))
|
||||||
|
.for("update")
|
||||||
.limit(1);
|
.limit(1);
|
||||||
|
|
||||||
if (existingSuperUser) {
|
if (existingSuperUser) {
|
||||||
|
|||||||
Reference in New Issue
Block a user