fix: resolve CREATE ROLE fusion_runtime race condition in migration 0006 (#2104)

## Summary

Fixes `CREATE ROLE fusion_runtime` race condition in migration
`0006_project_ownership.sql` that causes 30 compound-engineering test
failures on CI.

## Root Cause

Concurrent test databases on the same PostgreSQL service container race
on `CREATE ROLE fusion_runtime`: the `IF NOT EXISTS` check is not atomic
(roles are cluster-wide, not per-database). Between the check and the
`CREATE ROLE`, another session can create the role, causing error
`23505` (unique_violation).

## Fix

Replace the non-atomic `IF NOT EXISTS` guard with a `BEGIN...EXCEPTION
WHEN duplicate_object OR unique_violation THEN NULL; END;` block that
safely handles the race.

## Verification

| Check | Result |
|---|---|
| compound-engineering (pipeline-store + orchestrator + session-routes)
| ✅ 41 passed |
| Engine shard 1/2 | ✅ 3826 passed, 0 failed |
| Merge gate | ✅ 471 passed |
| Lint | ✅ exit 0 |
This commit is contained in:
gsxdsm
2026-07-14 20:48:30 -07:00
committed by GitHub
parent 51859148a7
commit f4e78abeb7

View File

@@ -42,14 +42,19 @@ BEGIN
PostgreSQL roles are cluster-wide while Gate databases apply this migration
concurrently. Advisory locks are database-local, so make CREATE ROLE itself
race-safe across databases by accepting the concurrent winner.
FNXC:ProjectDataIsolation 2026-07-15-01:50:
Always CREATE ROLE (no IF NOT EXISTS). The check-then-create path is not atomic
across databases of one cluster: concurrent appliers all observe the role as
absent and race on CREATE ROLE, raising 23505 on pg_authid_rolname_index.
EXCEPTION WHEN duplicate_object OR unique_violation tolerates losing that race
(unique_violation is what the index race actually raises).
*/
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'fusion_runtime') THEN
BEGIN
CREATE ROLE fusion_runtime NOLOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION;
EXCEPTION
WHEN duplicate_object OR unique_violation THEN NULL;
END;
END IF;
BEGIN
CREATE ROLE fusion_runtime NOLOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION;
EXCEPTION WHEN duplicate_object OR unique_violation THEN
NULL; -- concurrent applier created the role first; safe to skip
END;
EXECUTE format('GRANT fusion_runtime TO %I', current_user);
END IF;
END $$;