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
OWNER
in the project - to downgrade an existing
OWNER
to any other access level in the project - to remove an existing
OWNER
from the project
In other MRs:
- to select
OWNER
when inviting a new member to the project👉 !89209 (merged) - to invite a group to the project with
OWNER
access level👉 !89209 (merged) - to create a project access token with
OWNER
access level👉 !89114 (merged) - ensure both maintainers and owners receive access request notifications
👉 !90018 (merged) update the project teamowners
method 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
OWNER
access 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
OWNER
in the project. Upgrade should be allowed only tillMAINTAINER
access level. - cannot downgrade an existing
OWNER
to any other access level in the project. Edits should be disabled in the UI. - cannot remove an existing
OWNER
from the project.Remove
member button should not appear. - cannot invite a group to the project with
OWNER
access level. The maximum access level shown in the access level dropdown should beMAINTAINER
- cannot create a project access token with
OWNER
access level. The maximum access level shown in the access level dropdown should beMAINTAINER
Also covered in #368349 (closed)
master
(before change):
Testing locally - status on - 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 Information
under 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
MAINTAINER
there is noRemove
button beside theOWNER
direct 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)