Owner can manage project owners via UI
What does this MR do and why?
Allow users that are existing OWNERs:
- to upgrade an existing member to
OWNERin the project - to downgrade an existing
OWNERto any other access level in the project - to remove an existing
OWNERfrom the project
In other MRs:
- to select
OWNERwhen inviting a new member to the project👉 !89209 (merged) - to invite a group to the project with
OWNERaccess level👉 !89209 (merged) - to create a project access token with
OWNERaccess level👉 !89114 (merged) - ensure both maintainers and owners receive access request notifications
👉 !90018 (merged) update the project teamownersmethod to include direct project owners👉 !92871 (closed)updateowned_by?method to make its usage clear👉 !90365 (closed)
Any other users with a different access level other than OWNER in the project, should not be able to perform these actions, ie, a MAINTAINER in a project:
- cannot select
OWNERaccess level when inviting a new member to the project. The maximum access level shown in the access level dropdown should beMAINTAINER - cannot upgrade an existing member to
OWNERin the project. Upgrade should be allowed only tillMAINTAINERaccess level. - cannot downgrade an existing
OWNERto any other access level in the project. Edits should be disabled in the UI. - cannot remove an existing
OWNERfrom the project.Removemember button should not appear. - cannot invite a group to the project with
OWNERaccess level. The maximum access level shown in the access level dropdown should beMAINTAINER - cannot create a project access token with
OWNERaccess level. The maximum access level shown in the access level dropdown should beMAINTAINER
Also covered in #368349 (closed)
Testing locally - status on master (before change):
- Invite new member (only up to Maintainer)
- View memberships (only up to Maintainer)
Testing locally - status on this branch (after change):
Part 1: make someone else an Owner of a group project
-
View members page under
Project Informationunder any project under either a group OR a personal project. For the example below we'll use a group project. -
View an existing user, and notice the dropdown now includes
Owner
- Add an existing user with Owner status using the form via username (via email presumably works too, I didn't try it)
- See new member has Owner status, and original owner also is owner!
- Notes also include the badge annotation
Part 2: Verify Owner permissions
-
Create some issue under the project.
-
As an Admin, visit the user's profile in the Admin view
Owner access shown next to the project
- Impersonate them.
- See the Delete button, only available to Owners!
- In console, you can verify that your User can now do things:
> p = Project.find <ID of the project>
> u = User.find <ID of the new Owner user>
> i = Project.issues.last
> Ability.allowed?(u, :delete_issue, i)
#=> true
policy debugger output
[4] pry(main)> ip = IssuePolicy.new(u, i)
=> #<IssuePolicy (@tomasa.hegmann : Issue/498)>
[5] pry(main)> ip.debug(:destroy_issue)
- [0] prevent when all?(anonymous, ~public_project) ((@tomasa.hegmann : Project/35))
- [14] prevent when all?(archived, ~pending_delete) ((@tomasa.hegmann : Project/35))
- [21] prevent when all?(confidential, ~can_read_confidential) ((@tomasa.hegmann : Issue/498))
ProjectFeature Load (11.5ms) SELECT "project_features".* FROM "project_features" WHERE "project_features"."project_id" = 35 LIMIT 1 /*application:console,db_config_name:main,line:/home/charlie/.rbenv/gems/2.7.0/gems/marginalia-1.10.0/lib/marginalia/comment.rb:25:in `block in construct_comment'*/
- [28] prevent when issues_disabled ((@tomasa.hegmann : Project/35))
- [28] prevent when all?(~public_project, ~internal_access, ~project_allowed_for_job_token) ((@tomasa.hegmann : Project/35))
+ [58] enable when can?(:owner_access) ((@tomasa.hegmann : Project/35))
=> #<DeclarativePolicy::Runner::State:0x0000558f005d1260
@called_conditions=
#<Set: {"/dp/condition/DeclarativePolicy::Base/anonymous/User:9",
"/dp/condition/ProjectPolicy/archived/Project:35",
"/dp/condition/IssuePolicy/confidential/Issue:498",
"/dp/condition/ProjectPolicy/issues_disabled/User:9,Project:35",
"/dp/condition/ProjectPolicy/public_project/Project:35",
"/dp/condition/BasePolicy/admin/User:9",
"/dp/condition/BasePolicy/auditor/User:9",
"/dp/condition/ProjectPolicy/needs_new_sso_session/User:9,Project:35",
"/dp/condition/ProjectPolicy/owner/User:9,Project:35",
"/dp/condition/BasePolicy/visual_review_bot/User:9",
"/dp/condition/BasePolicy/security_bot/User:9",
"/dp/condition/BasePolicy/alert_bot/User:9",
"/dp/condition/BasePolicy/support_bot/User:9",
"/dp/condition/BasePolicy/external_authorization_enabled",
"/dp/condition/DeclarativePolicy::Base/default"}>,
@enabled=true,
@prevented=false>
Part 3: Do something now permissable
- Delete an issue impersonating that person, which is possible as an Owner but not a Maintainer in a group project
- success! issue gone!
🚀
Part 4: Misc
- External users can be owners and have a badge
- Adding another owner to a personal project does NOT give them the ability to remove the namespace's user as a member via the UI nor the REST API
(on my local @tomasa.hegmann has user id 9, and their personal project id is 18, of which @user1 is also an owner)
$ curl --request DELETE --header "PRIVATE-TOKEN: glpat-user1-token" "https://gdk.test:3443/api/v4/projects/18/members/9"
{"message":"403 Forbidden"}
-
Deleting the project! Can they do that?
-
As a
MAINTAINERthere is noRemovebutton beside theOWNERdirect users, nor is the dropdown to edit their role enabled.
MR acceptance checklist
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
-
I have evaluated the MR acceptance checklist for this MR.
Related to #21432 (closed)














