Grant the Organization Administrator role to owners created through Users::CreateService
What does this MR do and why?
Closes #630676 (closed).
Owners created through Users::CreateService never get the IAM organization_admin (Organization Administrator) tuple. Two paths write an owner membership without going through an organization-user service, so none of the existing sync hooks fire:
- The admin new-user form's "Organization administrator" option, which writes the membership through
Users::BuildService#assign_organization. - Users created with the admin flag, who get an owner row on their home organization from
Organizations::OrganizationUser.home_organization_access_level(user_is_admin: true).
This MR adds a hook to Users::CreateService#after_create_hook that enqueues Authz::Organizations::GrantOwnerRoleWorker for each owner membership of the new user, passing the creating admin as actor (nil when there is none, in which case the worker mints the token as the owner). The hook is gated by Authz::Organizations::OwnerRoleSync.enabled?, matching the other hooks in this series.
The hook does not try to distinguish why a row exists. That decision lives in the worker: per maintainer dlrussel's rule (!255373 (comment 3893548002)), the worker skips an owner row only when the user has the admin flag and the row is their home-organization membership. So an admin-flag user still enqueues a job, which the worker logs and skips, while a non-admin user created with "Organization administrator" gets the tuple granted.
This is split out of !255373 (merged) at reviewer skundapur's suggestion, so the other owner-creation paths could merge first. This MR targets that MR's branch and depends on it for the worker's all-owners mode and its instance-admin rule. It will be retargeted to master once 255373 merges.
The change is small: two files, about 80 lines including specs.
Known gaps and follow-ups
- A new instance admin created with "Organization administrator" explicitly selected writes the same home-organization owner row the admin flag would, so the worker cannot tell them apart and skips both. This is unsupported until IAM has an instance admin subject and role.
Users::ServiceAccounts::CreateServicereusesUsers::CreateService, but service accounts get the default access level, so nothing is enqueued for them. No change needed there.
References
- Closes #630676 (closed)
- Parent MR (worker implementation, targeted by this MR): !255373 (merged)
- Maintainer discussion establishing the admin-flag skip rule: !255373 (comment 3893548002)
- Closed beta blocker: gitlab-org/ops/artifact-registry#1326 (closed)
- Original contract: #601665 (closed)
Screenshots or screen recordings
Not applicable, this is a backend-only change.
How to set up and validate locally
Configure IAM data access (iam_data_access_service.secret_file in gitlab.yml) on an EE instance with a Cloud Connector key.
- In the admin area, create a new user, select "Organization administrator", and save. Confirm exactly one
GrantOwnerRoleWorkerjob is enqueued, with the new user's id and the creating admin's id. - Create a user with the admin flag set. Confirm a job is still enqueued, but the worker logs that the owner row comes from the instance admin flag and skips granting, without calling out to IAM.
- Create a regular user with no admin flag and no "Organization administrator" option. Confirm nothing is enqueued.
RuboCop is clean on both files. RSpec was not run locally because the test database cluster for this checkout is down, so the MR pipeline verifies the specs.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.