On Mon, Mar 16, 2026 at 5:19 PM Nathan Bossart <[email protected]> wrote: > This was added by commit ce6b672e44, which first took effect in v16. IIUC > earlier versions simply check is_admin_of_role() and mark the grantor as > the current role, at least when adding members. I haven't found any other > e-mails or documentation about this.
Thanks, Nathan, for pointing me to this thread. > Changing is_admin_of_role() to use ROLERECURSE_PRIVS would make things more > restrictive (e.g., the DROP ROLE in the test fails), which has the > potential to break existing scripts. But it does seem intuitive that if > you don't INHERIT a roles privileges, you don't inherit its ADMIN rights > either. I've been viewing ROLERECURSE_MEMBERS vs. ROLERECURSE_PRIVS vs. ROLERECURSE_SETROLE as somewhat orthogonal to ADMIN vs. MEMBER. Look at pg_role_aclcheck(): it tests is_member_of_role(), which uses ROLERECURSE_MEMBERS, for ACL_CREATE. So it seems like it would be surprising if when checking ACL_GRANT_OPTION_FOR(ACL_CREATE), it switched to using ROLERECURSE_PRIVS. On the other hand, check_role_grantor() checks has_privs_of_role(), which I strongly suspect is why select_best_admin(), called just after that check, uses ROLERECURSE_PRIVS. But I think my mental model here is actually a bit incoherent for ADMIN. We get into this problem because check_role_membership_authorization() decides whether you're allowed to tinker with a role using is_admin_of_role(), which searches with ROLERECURSE_MEMBERS, and then we call AddRoleMems() which calls check_role_grantor() which calls select_best_admin(), which uses a ROLERECURSE_PRIVS search and it expects that to succeed. I'm pretty strongly disinclined to change the meaning of is_admin_of_role() in released code. That affects more than this call site. When this code was under development, one of the use cases that was booted was a user management bot who should be able to run ALTER ROLE but should not automatically exercise the privilege of any created roles. If we standardize on ROLERECURSE_PRIVS, that use case doesn't work any more. You now have to inherit a role's privileges or AlterRole() will fail. One idea could be that non-membership changes to roles continue to work as they do today, but membership changes use ROLERECURSE_PRIVS. So we'd have is_admin_of_role() and inherits_admin_privs_for_role() and be careful to use the right one in each case. This seems a little weird, but I'm not sure what would be better. -- Robert Haas EDB: http://www.enterprisedb.com
