fix(controlplane): restrict owner-role invitations to org owners (CP-1)
Merged
MI
4mo ago+367+367+012345678901234567890123456789-165-165-012345678901234567890123456789
Fixes #3264
What
OrgInvitationUseCase.Create accepted any caller-supplied role verbatim. The Casbin authz middleware gates OrgInvitationService/Create with PolicyOrganizationInvitationsCreate (admin/owner only), but RoleAdmin.IsAdmin() short-circuits the middleware ā so an Admin could invite a new external email as MEMBERSHIP_ROLE_ORG_OWNER. AcceptPendingInvitations then auto-creates an Owner membership, bypassing PolicyOrganizationManageOwners (the Owner-only manage-owners gate) and bootstrapping a fresh Owner via the invitation path.
Change
- When the requested invitation role is
RoleOwner, the biz layer now enforcesPolicyOrganizationManageOwnersagainst the caller's authz subject. The check is shared with the existing owner-scoped guards inMembershipUseCase.UpdateRole/DeleteOtherthrough a singleenforceManageOwnershelper, with the denial messages defined once. Non-owner callers receiveErrUnauthorized("only organization owners can invite owners"). - The service layer passes the caller's authz subject (org role for users,
api-token:<id>for API tokens) down via a newcallerRoleparameter; the group/project invitation flows pass the requester's membership role. - This intentionally also applies to instance admins: they hold
PolicyOrganizationInvitationsCreatebut deliberately notPolicyOrganizationManageOwners, so they can no longer seed owners into organizations they administer. GroupUseCase.handleNonExistingUsernow guards against a nil requester membership instead of dereferencing it.
Parts of this change were produced with AI assistance (Claude Code); see the commit trailers.
š¤ Posted by Maximus bot (Claude Code) on behalf of @migmartri