@@ -45,6 +45,7 @@ type OrgInvitationUseCase struct {
4545 projectRepo ProjectsRepo
4646 // Use cases
4747 auditor * AuditorUseCase
48+ authzUC * AuthzUseCase
4849}
4950
5051type OrgInvitation struct {
@@ -83,10 +84,10 @@ type OrgInvitationRepo interface {
8384 ChangeStatus (ctx context.Context , ID uuid.UUID , status OrgInvitationStatus ) error
8485}
8586
86- func NewOrgInvitationUseCase (r OrgInvitationRepo , mRepo MembershipRepo , uRepo UserRepo , auditorUC * AuditorUseCase , groupRepo GroupRepo , projectRepo ProjectsRepo , l log.Logger ) (* OrgInvitationUseCase , error ) {
87+ func NewOrgInvitationUseCase (r OrgInvitationRepo , mRepo MembershipRepo , uRepo UserRepo , auditorUC * AuditorUseCase , groupRepo GroupRepo , projectRepo ProjectsRepo , authzUC * AuthzUseCase , l log.Logger ) (* OrgInvitationUseCase , error ) {
8788 return & OrgInvitationUseCase {
8889 logger : servicelogger .ScopedHelper (l , "biz/orgInvitation" ),
89- repo : r , mRepo : mRepo , userRepo : uRepo , auditor : auditorUC , groupRepo : groupRepo , projectRepo : projectRepo ,
90+ repo : r , mRepo : mRepo , userRepo : uRepo , auditor : auditorUC , groupRepo : groupRepo , projectRepo : projectRepo , authzUC : authzUC ,
9091 }, nil
9192}
9293
@@ -118,7 +119,7 @@ func WithSender(senderID uuid.UUID) InvitationCreateOpt {
118119 }
119120}
120121
121- func (uc * OrgInvitationUseCase ) Create (ctx context.Context , orgID , receiverEmail string , createOpts ... InvitationCreateOpt ) (* OrgInvitation , error ) {
122+ func (uc * OrgInvitationUseCase ) Create (ctx context.Context , orgID , receiverEmail string , callerRole authz. Role , createOpts ... InvitationCreateOpt ) (* OrgInvitation , error ) {
122123 ctx , span := otelx .Start (ctx , orgInvitationTracer , "OrgInvitationUseCase.Create" )
123124 defer span .End ()
124125
@@ -143,6 +144,14 @@ func (uc *OrgInvitationUseCase) Create(ctx context.Context, orgID, receiverEmail
143144 return nil , NewErrValidationStr ("role is required" )
144145 }
145146
147+ // Only owners can send owner invitations. This closes the Admin→Owner
148+ // invite bypass of PolicyOrganizationManageOwners.
149+ if opts .role == authz .RoleOwner {
150+ if err := enforceManageOwners (ctx , uc .authzUC , callerRole , errMsgOnlyOwnersInviteOwners ); err != nil {
151+ return nil , err
152+ }
153+ }
154+
146155 orgUUID , err := uuid .Parse (orgID )
147156 if err != nil {
148157 return nil , NewErrInvalidUUID (err )
0 commit comments