Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- role_permissions must be unique per property. The old unique index
-- (role_id, permission_key) made Cloud tenant bootstrap silently skip
-- permission grants once any other property had seeded the same system role.

DROP INDEX IF EXISTS role_permissions_role_perm_unique;

CREATE UNIQUE INDEX IF NOT EXISTS role_permissions_role_perm_unique
ON role_permissions (property_id, role_id, permission_key);
2 changes: 1 addition & 1 deletion packages/database/src/push-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,7 @@ async function main() {
permission_key varchar(100) NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
)`,
`CREATE UNIQUE INDEX IF NOT EXISTS role_permissions_role_perm_unique ON role_permissions (role_id, permission_key)`,
`CREATE UNIQUE INDEX IF NOT EXISTS role_permissions_role_perm_unique ON role_permissions (property_id, role_id, permission_key)`,
`CREATE TABLE IF NOT EXISTS user_roles (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
property_id uuid NOT NULL REFERENCES properties(id),
Expand Down
7 changes: 6 additions & 1 deletion packages/database/src/schema/rbac.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,12 @@ export const rolePermissions = pgTable(
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
},
(t) => ({
rolePermUnique: uniqueIndex('role_permissions_role_perm_unique').on(t.roleId, t.permissionKey),
// Grants are property-scoped even when role_id points at a global system role.
rolePermUnique: uniqueIndex('role_permissions_role_perm_unique').on(
t.propertyId,
t.roleId,
t.permissionKey,
),
}),
);

Expand Down
Loading