diff --git a/migrations/000029_rbac.up.sql b/migrations/000029_rbac.up.sql index 43e6da2..6870850 100644 --- a/migrations/000029_rbac.up.sql +++ b/migrations/000029_rbac.up.sql @@ -268,6 +268,16 @@ ON CONFLICT (role_id, permission_id, scope_type, scope_id) DO NOTHING; -- The row exists unconditionally; the env-var check happens in code. -- Reserved system actor: API rejects mutations / deletions targeting -- this id with 409 Conflict. +-- v2.1.0 Phase-9 cold-DB-smoke fix: this ON CONFLICT used to reference +-- UNIQUE (actor_id, actor_type, role_id, tenant_id), the constraint +-- created by this migration. Migration 000043 (Audit 2026-05-10 HIGH-10 +-- closure) drops that constraint and re-creates it with scope_type + +-- scope_id columns. On a re-run of this migration (which the naive +-- file-walking RunMigrations does on every server boot), the original +-- ON CONFLICT spec no longer matches an existing constraint and +-- Postgres errors out. Pin the conflict target to `id` (the PK column, +-- unconditionally present in both pre- and post-000043 schemas) so the +-- seed stays idempotent across migration-ordering changes downstream. INSERT INTO actor_roles (id, actor_id, actor_type, role_id, granted_at, granted_by, tenant_id) VALUES ( 'ar-demo-anon-admin', @@ -278,6 +288,6 @@ VALUES ( 'system', 't-default' ) -ON CONFLICT (actor_id, actor_type, role_id, tenant_id) DO NOTHING; +ON CONFLICT (id) DO NOTHING; COMMIT; diff --git a/migrations/000045_users_deactivated_at.up.sql b/migrations/000045_users_deactivated_at.up.sql index 700ee63..00a965a 100644 --- a/migrations/000045_users_deactivated_at.up.sql +++ b/migrations/000045_users_deactivated_at.up.sql @@ -19,21 +19,27 @@ BEGIN; ALTER TABLE users ADD COLUMN IF NOT EXISTS deactivated_at TIMESTAMPTZ; -INSERT INTO permissions (name) VALUES - ('auth.user.read'), - ('auth.user.deactivate') -ON CONFLICT (name) DO NOTHING; +-- v2.1.0 Phase-9 cold-DB-smoke fix: the original commit set just +-- (name) and used a `permission` column in role_permissions. The +-- 000029 schema actually defines `permissions (id PK, name UNIQUE, +-- namespace NOT NULL)` and `role_permissions (..., permission_id, ...)`. +-- testcontainers schema-per-test never exercised this path; the cold +-- compose-up smoke caught it on a fresh Postgres. +INSERT INTO permissions (id, name, namespace) VALUES + ('p-auth-user-read', 'auth.user.read', 'auth.user'), + ('p-auth-user-deactivate', 'auth.user.deactivate', 'auth.user') +ON CONFLICT (id) DO NOTHING; -- Read is broad (admin / operator / auditor). -INSERT INTO role_permissions (role_id, permission, scope_type, scope_id) VALUES - ('r-admin', 'auth.user.read', 'global', NULL), - ('r-operator', 'auth.user.read', 'global', NULL), - ('r-auditor', 'auth.user.read', 'global', NULL) -ON CONFLICT DO NOTHING; +INSERT INTO role_permissions (role_id, permission_id, scope_type, scope_id) VALUES + ('r-admin', 'p-auth-user-read', 'global', NULL), + ('r-operator', 'p-auth-user-read', 'global', NULL), + ('r-auditor', 'p-auth-user-read', 'global', NULL) +ON CONFLICT (role_id, permission_id, scope_type, scope_id) DO NOTHING; -- Deactivate is admin-only. -INSERT INTO role_permissions (role_id, permission, scope_type, scope_id) VALUES - ('r-admin', 'auth.user.deactivate', 'global', NULL) -ON CONFLICT DO NOTHING; +INSERT INTO role_permissions (role_id, permission_id, scope_type, scope_id) VALUES + ('r-admin', 'p-auth-user-deactivate', 'global', NULL) +ON CONFLICT (role_id, permission_id, scope_type, scope_id) DO NOTHING; COMMIT;