diff --git a/backend/src/db/migrations/20251023121055_fix-missing-group-memberships.ts b/backend/src/db/migrations/20251023121055_fix-missing-group-memberships.ts new file mode 100644 index 000000000..e4af23c46 --- /dev/null +++ b/backend/src/db/migrations/20251023121055_fix-missing-group-memberships.ts @@ -0,0 +1,45 @@ +import { Knex } from "knex"; + +import { AccessScope, TableName } from "../schemas"; + +export async function up(knex: Knex): Promise { + const hasGroupsTable = await knex.schema.hasTable(TableName.Groups); + const hasMembershipTable = await knex.schema.hasTable(TableName.Membership); + + if (!hasGroupsTable || !hasMembershipTable) { + return; + } + + const groupsWithoutMembership = await knex + .select(`${TableName.Groups}.id`, `${TableName.Groups}.orgId`) + .from(TableName.Groups) + .leftJoin(TableName.Membership, function joinGroupMembership() { + this.on(`${TableName.Groups}.id`, "=", `${TableName.Membership}.actorGroupId`); + }) + .whereNull(`${TableName.Membership}.actorGroupId`); + + if (groupsWithoutMembership.length > 0) { + const membershipInserts = groupsWithoutMembership.map((group) => ({ + actorGroupId: group.id, + scope: AccessScope.Organization, + scopeOrgId: group.orgId, + isActive: true + })); + + await knex(TableName.Membership).insert(membershipInserts); + } + + await knex.schema.alterTable(TableName.Membership, (t) => { + t.check( + `("actorUserId" IS NOT NULL OR "actorIdentityId" IS NOT NULL OR "actorGroupId" IS NOT NULL)`, + undefined, + "at_least_one_actor" + ); + }); +} + +export async function down(knex: Knex): Promise { + await knex.schema.alterTable(TableName.Membership, (t) => { + t.dropChecks("at_least_one_actor"); + }); +} diff --git a/backend/src/ee/services/saml-config/saml-config-service.ts b/backend/src/ee/services/saml-config/saml-config-service.ts index 13b862343..f9c97fc6f 100644 --- a/backend/src/ee/services/saml-config/saml-config-service.ts +++ b/backend/src/ee/services/saml-config/saml-config-service.ts @@ -84,7 +84,7 @@ type TSamlConfigServiceFactoryDep = { projectDAL: Pick; projectBotDAL: Pick; projectKeyDAL: Pick; - membershipGroupDAL: Pick; + membershipGroupDAL: Pick; }; export const samlConfigServiceFactory = ({ @@ -183,6 +183,14 @@ export const samlConfigServiceFactory = ({ transaction ); orgGroupsMap.set(groupName, newGroup); + await membershipGroupDAL.create( + { + actorGroupId: newGroup.id, + scope: AccessScope.Organization, + scopeOrgId: orgId + }, + transaction + ); } }