From 942add7a5210edce018078f7454bbed897f4c2d6 Mon Sep 17 00:00:00 2001 From: Milan Pavlik Date: Tue, 11 Oct 2022 08:14:22 +0000 Subject: [PATCH] [server] Prevent changing role for teams of size 1 --- components/gitpod-db/src/typeorm/team-db-impl.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/components/gitpod-db/src/typeorm/team-db-impl.ts b/components/gitpod-db/src/typeorm/team-db-impl.ts index 5a1ed24a53d7aa..dcb992a123f4e4 100644 --- a/components/gitpod-db/src/typeorm/team-db-impl.ts +++ b/components/gitpod-db/src/typeorm/team-db-impl.ts @@ -7,7 +7,7 @@ import { list as blocklist } from "the-big-username-blacklist"; import { Team, TeamMemberInfo, TeamMemberRole, TeamMembershipInvite, User } from "@gitpod/gitpod-protocol"; import { inject, injectable } from "inversify"; -import { TypeORM } from "./typeorm"; +import { TypeORM, Not } from "./typeorm"; import { Repository } from "typeorm"; import { v4 as uuidv4 } from "uuid"; import { TeamDB } from "../team-db"; @@ -203,6 +203,19 @@ export class TeamDBImpl implements TeamDB { throw new ResponseError(ErrorCodes.NOT_FOUND, "A team with this ID could not be found"); } const membershipRepo = await this.getMembershipRepo(); + + if (role != "owner") { + const ownerCountAfterChange = await membershipRepo.count({ + teamId, + userId: Not(userId), + role: "owner", + deleted: false, + }); + if (ownerCountAfterChange < 1) { + throw new ResponseError(ErrorCodes.CONFLICT, "Team must retain at least one owner"); + } + } + const membership = await membershipRepo.findOne({ teamId, userId, deleted: false }); if (!membership) { throw new ResponseError(ErrorCodes.NOT_FOUND, "The user is not currently a member of this team");