From 97135d9cfa1410307876ac75626206f16dac0379 Mon Sep 17 00:00:00 2001 From: = Date: Thu, 9 Oct 2025 00:45:49 +0530 Subject: [PATCH] feat: go greppy --- .../20251005152640_simplify-membership.ts | 3 +- ...ity-project-additional-privilege-router.ts | 1 - .../github-org-sync-service.ts | 48 ++++++++++++++++++- .../group/user-group-membership-dal.ts | 2 +- .../src/ee/services/license/license-dal.ts | 2 +- .../ee/services/permission/org-permission.ts | 8 +++- .../ee/services/permission/permission-dal.ts | 5 +- .../permission/permission-service-types.ts | 7 ++- .../services/permission/permission-service.ts | 4 -- backend/src/ee/services/scim/scim-service.ts | 13 +++-- .../secret-approval-request-dal.ts | 23 ++++----- backend/src/server/routes/index.ts | 5 +- .../server/routes/v1/group-project-router.ts | 2 +- .../v2/deprecated-group-project-router.ts | 2 +- .../server/routes/v2/organization-router.ts | 3 +- .../additional-privilege-service.ts | 6 +-- .../services/convertor/convertor-service.ts | 4 +- .../external-migration-service.ts | 6 +-- .../group-project/group-project-dal.ts | 1 - .../identity-oidc-auth-service.ts | 2 +- .../identity-project/identity-project-dal.ts | 2 +- .../identity-project-service.ts | 2 +- .../identity-tls-cert-auth-service.ts | 9 ++-- .../src/services/identity/identity-org-dal.ts | 2 +- .../membership-group/membership-group-dal.ts | 6 +-- .../membership-group-service.ts | 4 +- .../org/org-membership-group-factory.ts | 2 +- .../project-membership-group-factory.ts | 2 +- .../membership-identity-dal.ts | 6 +-- .../membership-identity-service.ts | 4 +- .../namespace-membership-identity-factory.ts | 12 ++--- .../org/org-membership-identity-factory.ts | 4 +- .../project-membership-identity-factory.ts | 2 +- .../membership-user/membership-user-dal.ts | 8 ++-- .../membership-user-service.ts | 8 ++-- .../org-membership/org-membership-dal.ts | 4 ++ backend/src/services/org/org-dal.ts | 2 +- .../services/project-key/project-key-dal.ts | 4 +- .../project-membership-dal.ts | 7 +-- backend/src/services/project/project-dal.ts | 1 - backend/src/services/role/role-service.ts | 4 +- .../super-admin/super-admin-service.ts | 5 +- frontend/src/hooks/api/users/types.ts | 1 + .../IdentityAuthTemplatesTable.tsx | 2 +- .../ExternalMigrationsTab.tsx | 2 +- .../components/UserDetailsSection.tsx | 4 +- 46 files changed, 150 insertions(+), 106 deletions(-) diff --git a/backend/src/db/migrations/20251005152640_simplify-membership.ts b/backend/src/db/migrations/20251005152640_simplify-membership.ts index 25fd19070..ff2987da7 100644 --- a/backend/src/db/migrations/20251005152640_simplify-membership.ts +++ b/backend/src/db/migrations/20251005152640_simplify-membership.ts @@ -665,7 +665,7 @@ export async function up(knex: Knex): Promise { await createAdditionalPrivilegeTable(knex); } - // no mean this has been created before + // this means these tables have been created before if (hasToMigrateMembershipTable) { await migrateMembershipData(knex); } @@ -784,7 +784,6 @@ const rollbackMembershipRoleData = async (knex: Knex) => { knex(TableName.MembershipRole) .join(TableName.Membership, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`) .join(TableName.Groups, `${TableName.Membership}.actorGroupId`, `${TableName.Groups}.id`) - .where(`${TableName.Membership}.scope`, AccessScope.Organization) .whereNotNull(`${TableName.Membership}.actorGroupId`) .where(`${TableName.Membership}.scope`, AccessScope.Organization) .select( diff --git a/backend/src/ee/routes/v1/identity-project-additional-privilege-router.ts b/backend/src/ee/routes/v1/identity-project-additional-privilege-router.ts index 57c5c8b9a..5a6cea20f 100644 --- a/backend/src/ee/routes/v1/identity-project-additional-privilege-router.ts +++ b/backend/src/ee/routes/v1/identity-project-additional-privilege-router.ts @@ -281,7 +281,6 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F }, data: { ...req.body, - isTemporary: true, ...updatedInfo, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore-error this is valid ts diff --git a/backend/src/ee/services/github-org-sync/github-org-sync-service.ts b/backend/src/ee/services/github-org-sync/github-org-sync-service.ts index 47bdd96ea..73b310340 100644 --- a/backend/src/ee/services/github-org-sync/github-org-sync-service.ts +++ b/backend/src/ee/services/github-org-sync/github-org-sync-service.ts @@ -6,13 +6,15 @@ import { paginateGraphql } from "@octokit/plugin-paginate-graphql"; import { Octokit as OctokitRest } from "@octokit/rest"; import RE2 from "re2"; -import { OrgMembershipRole } from "@app/db/schemas"; +import { AccessScope, OrgMembershipRole } from "@app/db/schemas"; import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { groupBy } from "@app/lib/fn"; import { logger } from "@app/lib/logger"; import { retryWithBackoff } from "@app/lib/retry"; import { TKmsServiceFactory } from "@app/services/kms/kms-service"; import { KmsDataKey } from "@app/services/kms/kms-types"; +import { TMembershipRoleDALFactory } from "@app/services/membership/membership-role-dal"; +import { TMembershipGroupDALFactory } from "@app/services/membership-group/membership-group-dal"; import { TOrgMembershipDALFactory } from "@app/services/org-membership/org-membership-dal"; import { TGroupDALFactory } from "../group/group-dal"; @@ -77,6 +79,8 @@ type TGithubOrgSyncServiceFactoryDep = { "findGroupMembershipsByUserIdInOrg" | "findGroupMembershipsByGroupIdInOrg" | "insertMany" | "delete" >; groupDAL: Pick; + membershipRoleDAL: Pick; + membershipGroupDAL: Pick; licenseService: Pick; orgMembershipDAL: Pick; }; @@ -90,7 +94,9 @@ export const githubOrgSyncServiceFactory = ({ userGroupMembershipDAL, groupDAL, licenseService, - orgMembershipDAL + orgMembershipDAL, + membershipRoleDAL, + membershipGroupDAL }: TGithubOrgSyncServiceFactoryDep) => { const createGithubOrgSync = async ({ githubOrgName, @@ -365,6 +371,25 @@ export const githubOrgSyncServiceFactory = ({ })), tx ); + const memberships = await membershipGroupDAL.insertMany( + newGroups.map( + (el) => ({ + actorGroupId: el.id, + scope: AccessScope.Organization, + scopeOrgId: orgId + }), + tx + ) + ); + + await membershipRoleDAL.insertMany( + memberships.map((el) => ({ + membershipId: el.id, + role: OrgMembershipRole.Member + })), + tx + ); + await userGroupMembershipDAL.insertMany( newGroups.map((el) => ({ groupId: el.id, @@ -691,6 +716,25 @@ export const githubOrgSyncServiceFactory = ({ tx ); + const memberships = await membershipGroupDAL.insertMany( + newGroups.map( + (el) => ({ + actorGroupId: el.id, + scope: AccessScope.Organization, + scopeOrgId: orgPermission.orgId + }), + tx + ) + ); + + await membershipRoleDAL.insertMany( + memberships.map((el) => ({ + membershipId: el.id, + role: OrgMembershipRole.Member + })), + tx + ); + newGroups.forEach((group) => { if (!existingTeamsMap[group.name]) { existingTeamsMap[group.name] = []; diff --git a/backend/src/ee/services/group/user-group-membership-dal.ts b/backend/src/ee/services/group/user-group-membership-dal.ts index f3e0a34c6..886eebe29 100644 --- a/backend/src/ee/services/group/user-group-membership-dal.ts +++ b/backend/src/ee/services/group/user-group-membership-dal.ts @@ -71,7 +71,7 @@ export const userGroupMembershipDALFactory = (db: TDbClient) => { const groups: string[] = await (tx || db.replicaNode())(TableName.Membership) .where(`${TableName.Membership}.scopeProjectId`, projectId) .whereNot(`${TableName.Membership}.actorGroupId`, groupId) - .pluck(`${TableName.Membership}.groupId`); + .pluck(`${TableName.Membership}.actorGroupId`); // main query const members = await (tx || db.replicaNode())(TableName.UserGroupMembership) diff --git a/backend/src/ee/services/license/license-dal.ts b/backend/src/ee/services/license/license-dal.ts index 46630f7f1..891d60922 100644 --- a/backend/src/ee/services/license/license-dal.ts +++ b/backend/src/ee/services/license/license-dal.ts @@ -36,7 +36,7 @@ export const licenseDALFactory = (db: TDbClient) => { void bd.where(`${TableName.Membership}.scopeOrgId`, orgId); } }) - .join(TableName.Users, `${TableName.Membership}.userId`, `${TableName.Users}.id`) + .join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`) .where(`${TableName.Users}.isGhost`, false) .count(); diff --git a/backend/src/ee/services/permission/org-permission.ts b/backend/src/ee/services/permission/org-permission.ts index 0548911e8..7bd12de51 100644 --- a/backend/src/ee/services/permission/org-permission.ts +++ b/backend/src/ee/services/permission/org-permission.ts @@ -219,7 +219,9 @@ export const OrgPermissionSchema = z.discriminatedUnion("subject", [ }), z.object({ subject: z.literal(OrgPermissionSubjects.Groups).describe("The entity this permission pertains to."), - action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionActions).describe("Describe what action an entity can take.") + action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionGroupActions).describe( + "Describe what action an entity can take." + ) }), z.object({ subject: z.literal(OrgPermissionSubjects.SecretScanning).describe("The entity this permission pertains to."), @@ -231,7 +233,9 @@ export const OrgPermissionSchema = z.discriminatedUnion("subject", [ }), z.object({ subject: z.literal(OrgPermissionSubjects.Identity).describe("The entity this permission pertains to."), - action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionActions).describe("Describe what action an entity can take.") + action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionIdentityActions).describe( + "Describe what action an entity can take." + ) }), z.object({ subject: z.literal(OrgPermissionSubjects.Kms).describe("The entity this permission pertains to."), diff --git a/backend/src/ee/services/permission/permission-dal.ts b/backend/src/ee/services/permission/permission-dal.ts index 5fb36cdee..49a375f8f 100644 --- a/backend/src/ee/services/permission/permission-dal.ts +++ b/backend/src/ee/services/permission/permission-dal.ts @@ -18,6 +18,7 @@ import { ActorType } from "@app/services/auth/auth-type"; interface TPermissionDataReturn extends TMemberships { orgAuthEnforced?: boolean | null; orgGoogleSsoAuthEnforced?: boolean | null; + shouldUseNewPrivilegeSystem?: boolean | null; bypassOrgAuthEnabled?: boolean | null; roles: { id: string; @@ -223,8 +224,7 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => { } else if (scopeData.scope === AccessScope.Namespace) { void qb .where(`${TableName.Membership}.scope`, AccessScope.Namespace) - .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId) - .whereNull(`${TableName.Membership}.scopeNamespaceId`); + .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId); } else if (scopeData.scope === AccessScope.Project) { void qb .where(`${TableName.Membership}.scope`, AccessScope.Project) @@ -282,6 +282,7 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => { parentMapper: (el) => MembershipsSchema.extend({ orgAuthEnforced: z.boolean().optional().nullable(), + shouldUseNewPrivilegeSystem: z.boolean().optional().nullable(), orgGoogleSsoAuthEnforced: z.boolean(), bypassOrgAuthEnabled: z.boolean() }).parse(el), diff --git a/backend/src/ee/services/permission/permission-service-types.ts b/backend/src/ee/services/permission/permission-service-types.ts index c333e5784..1f0e00470 100644 --- a/backend/src/ee/services/permission/permission-service-types.ts +++ b/backend/src/ee/services/permission/permission-service-types.ts @@ -66,7 +66,12 @@ export type TPermissionServiceFactory = { actorOrgId: string | undefined ) => Promise<{ permission: MongoAbility; - memberships: Array; + memberships: Array< + TMemberships & { + roles: { role: string; customRoleSlug?: string | null }[]; + shouldUseNewPrivilegeSystem?: boolean | null; + } + >; hasRole: (role: string) => boolean; }>; getProjectPermission: (arg: TGetProjectPermissionArg) => Promise<{ diff --git a/backend/src/ee/services/permission/permission-service.ts b/backend/src/ee/services/permission/permission-service.ts index c227eb6ba..2d879b4fd 100644 --- a/backend/src/ee/services/permission/permission-service.ts +++ b/backend/src/ee/services/permission/permission-service.ts @@ -258,10 +258,6 @@ export const permissionServiceFactory = ({ if (!serviceTokenProject) throw new BadRequestError({ message: "Service token not linked to a project" }); - if (serviceTokenProject.orgId !== actorOrgId) { - throw new ForbiddenRequestError({ message: "Service token not a part of the specified organization" }); - } - if (serviceToken.projectId !== projectId) { throw new ForbiddenRequestError({ name: `Service token not a part of the specified project with ID ${projectId}` diff --git a/backend/src/ee/services/scim/scim-service.ts b/backend/src/ee/services/scim/scim-service.ts index 14a83d1f9..24a3097b0 100644 --- a/backend/src/ee/services/scim/scim-service.ts +++ b/backend/src/ee/services/scim/scim-service.ts @@ -354,11 +354,14 @@ export const scimServiceFactory = ({ }, tx ); - await membershipRoleDAL.create({ - membershipId: orgMembership.id, - role, - customRoleId: roleId - }); + await membershipRoleDAL.create( + { + membershipId: orgMembership.id, + role, + customRoleId: roleId + }, + tx + ); } else if (orgMembership.status === OrgMembershipStatus.Invited && user.isAccepted) { orgMembership = await membershipUserDAL.updateById( orgMembership.id, diff --git a/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts b/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts index 42e6da268..7597dcfd4 100644 --- a/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts +++ b/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts @@ -37,6 +37,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { .where(filter) .join(TableName.SecretFolder, `${TableName.SecretApprovalRequest}.folderId`, `${TableName.SecretFolder}.id`) .join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`) + .join(TableName.Project, `${TableName.Environment}.projectId`, `${TableName.Project}.id`) .join( TableName.SecretApprovalPolicy, `${TableName.SecretApprovalRequest}.policyId`, @@ -111,24 +112,20 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { ) .leftJoin(db(TableName.Membership).as("approverOrgMembership"), (qb) => { - qb.on(`${TableName.SecretApprovalPolicyApprover}.approverUserId`, `approverOrgMembership.actorUserId`).andOn( - `approverOrgMembership.scope`, - db.raw("?", [AccessScope.Organization]) - ); + qb.on(`${TableName.SecretApprovalPolicyApprover}.approverUserId`, `approverOrgMembership.actorUserId`) + .andOn(`approverOrgMembership.scopeOrgId`, `${TableName.Project}.orgId`) + .andOn(`approverOrgMembership.scope`, db.raw("?", [AccessScope.Organization])); }) .leftJoin(db(TableName.Membership).as("approverGroupOrgMembership"), (qb) => { - qb.on(`secretApprovalPolicyGroupApproverUser.id`, `approverGroupOrgMembership.actorUserId`).andOn( - `approverGroupOrgMembership.scope`, - db.raw("?", [AccessScope.Organization]) - ); + qb.on(`secretApprovalPolicyGroupApproverUser.id`, `approverGroupOrgMembership.actorUserId`) + .andOn(`approverGroupOrgMembership.scopeOrgId`, `${TableName.Project}.orgId`) + .andOn(`approverGroupOrgMembership.scope`, db.raw("?", [AccessScope.Organization])); }) - .leftJoin(db(TableName.Membership).as("reviewerOrgMembership"), (qb) => { - qb.on(`${TableName.SecretApprovalRequestReviewer}.reviewerUserId`, `reviewerOrgMembership.actorUserId`).andOn( - `reviewerOrgMembership.scope`, - db.raw("?", [AccessScope.Organization]) - ); + qb.on(`${TableName.SecretApprovalRequestReviewer}.reviewerUserId`, `reviewerOrgMembership.actorUserId`) + .andOn(`reviewerOrgMembership.scopeOrgId`, `${TableName.Project}.orgId`) + .andOn(`reviewerOrgMembership.scope`, db.raw("?", [AccessScope.Organization])); }) .select(selectAllTableCols(TableName.SecretApprovalRequest)) .select( diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index d2d44002c..824f5384c 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -778,7 +778,9 @@ export const registerRoutes = async ( permissionService, groupDAL, userGroupMembershipDAL, - orgMembershipDAL + orgMembershipDAL, + membershipRoleDAL, + membershipGroupDAL }); const ldapService = ldapConfigServiceFactory({ @@ -1643,7 +1645,6 @@ export const registerRoutes = async ( const identityTlsCertAuthService = identityTlsCertAuthServiceFactory({ identityAccessTokenDAL, - orgDAL, identityTlsCertAuthDAL, licenseService, permissionService, diff --git a/backend/src/server/routes/v1/group-project-router.ts b/backend/src/server/routes/v1/group-project-router.ts index 5957daddb..93caf5035 100644 --- a/backend/src/server/routes/v1/group-project-router.ts +++ b/backend/src/server/routes/v1/group-project-router.ts @@ -12,10 +12,10 @@ import { import { EFilterReturnedUsers } from "@app/ee/services/group/group-types"; import { ApiDocsTags, GROUPS, PROJECTS } from "@app/lib/api-docs"; import { ms } from "@app/lib/ms"; +import { isUuidV4 } from "@app/lib/validator"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; -import { isUuidV4 } from "@app/lib/validator"; export const registerGroupProjectRouter = async (server: FastifyZodProvider) => { server.route({ diff --git a/backend/src/server/routes/v2/deprecated-group-project-router.ts b/backend/src/server/routes/v2/deprecated-group-project-router.ts index ca7753039..5be7df838 100644 --- a/backend/src/server/routes/v2/deprecated-group-project-router.ts +++ b/backend/src/server/routes/v2/deprecated-group-project-router.ts @@ -12,10 +12,10 @@ import { import { EFilterReturnedUsers } from "@app/ee/services/group/group-types"; import { ApiDocsTags, GROUPS, PROJECTS } from "@app/lib/api-docs"; import { ms } from "@app/lib/ms"; +import { isUuidV4 } from "@app/lib/validator"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; -import { isUuidV4 } from "@app/lib/validator"; export const registerDeprecatedGroupProjectRouter = async (server: FastifyZodProvider) => { server.route({ diff --git a/backend/src/server/routes/v2/organization-router.ts b/backend/src/server/routes/v2/organization-router.ts index 2db7b90b1..93320f3e0 100644 --- a/backend/src/server/routes/v2/organization-router.ts +++ b/backend/src/server/routes/v2/organization-router.ts @@ -139,6 +139,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { response: { 200: z.object({ membership: OrgMembershipsSchema.extend({ + customRoleSlug: z.string().nullish(), metadata: z .object({ key: z.string().trim().min(1), @@ -224,7 +225,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { return { membership: { ...membership, - role: "", + role: req.body.role || "", orgId: req.params.organizationId, status: membership.status || OrgMembershipStatus.Accepted } diff --git a/backend/src/services/additional-privilege/additional-privilege-service.ts b/backend/src/services/additional-privilege/additional-privilege-service.ts index 4b7f78441..2af9e6419 100644 --- a/backend/src/services/additional-privilege/additional-privilege-service.ts +++ b/backend/src/services/additional-privilege/additional-privilege-service.ts @@ -63,7 +63,7 @@ export const additionalPrivilegeServiceFactory = ({ [dbActorField]: data.actorId, [scope.key]: scope.value }); - if (existingSlug) throw new BadRequestError({ message: `Additional privilege with name ${data.name} exist` }); + if (existingSlug) throw new BadRequestError({ message: `Additional privilege with name ${data.name} exists` }); validateHandlebarTemplate("Additional Privilege Create", JSON.stringify(data.permissions || []), { allowedExpressions: (val) => val.includes("identity.") @@ -115,12 +115,12 @@ export const additionalPrivilegeServiceFactory = ({ const dbActorField = dto.selector.actorType === ActorType.IDENTITY ? "actorIdentityId" : "actorUserId"; const existingPrivilege = await additionalPrivilegeDAL.findOne({ - id: dto.selector.id, [dbActorField]: dto.selector.actorId, + id: dto.selector.id, [scope.key]: scope.value }); if (!existingPrivilege) - throw new NotFoundError({ message: `Additional privilege with name ${data.name} doesn't exist` }); + throw new NotFoundError({ message: `Additional privilege with id ${dto.selector.id} doesn't exist` }); validateHandlebarTemplate("Additional Privilege Create", JSON.stringify(data.permissions || []), { allowedExpressions: (val) => val.includes("identity.") diff --git a/backend/src/services/convertor/convertor-service.ts b/backend/src/services/convertor/convertor-service.ts index 4165d8836..71c25e9c0 100644 --- a/backend/src/services/convertor/convertor-service.ts +++ b/backend/src/services/convertor/convertor-service.ts @@ -1,10 +1,10 @@ import { AccessScope } from "@app/db/schemas"; +import { TGroupDALFactory } from "@app/ee/services/group/group-dal"; import { NotFoundError } from "@app/lib/errors"; import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal"; import { TMembershipDALFactory } from "../membership/membership-dal"; import { TProjectDALFactory } from "../project/project-dal"; -import { TGroupDALFactory } from "@app/ee/services/group/group-dal"; type TConvertorServiceFactoryDep = { projectDAL: Pick; @@ -105,7 +105,7 @@ export const convertorServiceFactory = ({ projectId }); if (!privilege) { - throw new NotFoundError({ message: `Privilege with slug ${privilegeName} not found` }); + throw new NotFoundError({ message: `Privilege with name ${privilegeName} not found` }); } return { privilegeId: privilege.id, privilege }; diff --git a/backend/src/services/external-migration/external-migration-service.ts b/backend/src/services/external-migration/external-migration-service.ts index 577712b9f..14885b1d6 100644 --- a/backend/src/services/external-migration/external-migration-service.ts +++ b/backend/src/services/external-migration/external-migration-service.ts @@ -54,7 +54,7 @@ export const externalMigrationServiceFactory = ({ actorAuthMethod, actorOrgId ); - if (hasRole(OrgMembershipRole.Admin)) { + if (!hasRole(OrgMembershipRole.Admin)) { throw new ForbiddenRequestError({ message: "Only admins can import data" }); } @@ -102,7 +102,7 @@ export const externalMigrationServiceFactory = ({ actorOrgId ); - if (hasRole(OrgMembershipRole.Admin)) { + if (!hasRole(OrgMembershipRole.Admin)) { throw new ForbiddenRequestError({ message: "Only admins can import data" }); } @@ -158,7 +158,7 @@ export const externalMigrationServiceFactory = ({ actorOrgId ); - if (hasRole(OrgMembershipRole.Admin)) { + if (!hasRole(OrgMembershipRole.Admin)) { throw new ForbiddenRequestError({ message: "Only admins can check custom migration status" }); } diff --git a/backend/src/services/group-project/group-project-dal.ts b/backend/src/services/group-project/group-project-dal.ts index d4a093b83..4d14758dc 100644 --- a/backend/src/services/group-project/group-project-dal.ts +++ b/backend/src/services/group-project/group-project-dal.ts @@ -29,7 +29,6 @@ export const groupProjectDALFactory = (db: TDbClient) => { db.ref("id").as("groupId").withSchema(TableName.Groups), db.ref("name").as("groupName").withSchema(TableName.Groups), db.ref("slug").as("groupSlug").withSchema(TableName.Groups), - db.ref("id").withSchema(TableName.Membership), db.ref("role").withSchema(TableName.MembershipRole), db.ref("id").withSchema(TableName.MembershipRole).as("membershipRoleId"), db.ref("customRoleId").withSchema(TableName.MembershipRole), diff --git a/backend/src/services/identity-oidc-auth/identity-oidc-auth-service.ts b/backend/src/services/identity-oidc-auth/identity-oidc-auth-service.ts index e2dddf7ec..1218d8e1c 100644 --- a/backend/src/services/identity-oidc-auth/identity-oidc-auth-service.ts +++ b/backend/src/services/identity-oidc-auth/identity-oidc-auth-service.ts @@ -257,7 +257,7 @@ export const identityOidcAuthServiceFactory = ({ identityId }); if (!identityMembershipOrg) { - if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` }); + throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` }); } if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OIDC_AUTH)) { throw new BadRequestError({ diff --git a/backend/src/services/identity-project/identity-project-dal.ts b/backend/src/services/identity-project/identity-project-dal.ts index 42fc1816b..3dba6210d 100644 --- a/backend/src/services/identity-project/identity-project-dal.ts +++ b/backend/src/services/identity-project/identity-project-dal.ts @@ -429,7 +429,7 @@ export const identityProjectDALFactory = (db: TDbClient) => { .join(TableName.Identity, `${TableName.Membership}.actorIdentityId`, `${TableName.Identity}.id`) .where((qb) => { if (filter.identityId) { - void qb.where("identityId", filter.identityId); + void qb.where(`${TableName.Membership}.actorIdentityId`, filter.identityId); } if (filter.search) { diff --git a/backend/src/services/identity-project/identity-project-service.ts b/backend/src/services/identity-project/identity-project-service.ts index 8cbed7d44..abe0446da 100644 --- a/backend/src/services/identity-project/identity-project-service.ts +++ b/backend/src/services/identity-project/identity-project-service.ts @@ -15,7 +15,7 @@ import { type TIdentityProjectServiceFactoryDep = { identityProjectDAL: TIdentityProjectDALFactory; - permissionService: Pick; + permissionService: Pick; membershipIdentityDAL: TMembershipIdentityDALFactory; }; diff --git a/backend/src/services/identity-tls-cert-auth/identity-tls-cert-auth-service.ts b/backend/src/services/identity-tls-cert-auth/identity-tls-cert-auth-service.ts index 54d2146cd..625b9b328 100644 --- a/backend/src/services/identity-tls-cert-auth/identity-tls-cert-auth-service.ts +++ b/backend/src/services/identity-tls-cert-auth/identity-tls-cert-auth-service.ts @@ -20,7 +20,6 @@ import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identit import { TKmsServiceFactory } from "../kms/kms-service"; import { KmsDataKey } from "../kms/kms-types"; import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal"; -import { TOrgDALFactory } from "../org/org-dal"; import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns"; import { TIdentityTlsCertAuthDALFactory } from "./identity-tls-cert-auth-dal"; import { TIdentityTlsCertAuthServiceFactory } from "./identity-tls-cert-auth-types"; @@ -35,7 +34,6 @@ type TIdentityTlsCertAuthServiceFactoryDep = { licenseService: Pick; permissionService: Pick; kmsService: Pick; - orgDAL: Pick; }; const parseSubjectDetails = (data: string) => { @@ -53,8 +51,7 @@ export const identityTlsCertAuthServiceFactory = ({ membershipIdentityDAL, licenseService, permissionService, - kmsService, - orgDAL + kmsService }: TIdentityTlsCertAuthServiceFactoryDep): TIdentityTlsCertAuthServiceFactory => { const login: TIdentityTlsCertAuthServiceFactory["login"] = async ({ identityId, clientCertificate }) => { const identityTlsCertAuth = await identityTlsCertAuthDAL.findOne({ identityId }); @@ -411,7 +408,7 @@ export const identityTlsCertAuthServiceFactory = ({ ); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity); - const { permission: rolePermission } = await permissionService.getOrgPermission( + const { permission: rolePermission, memberships } = await permissionService.getOrgPermission( ActorType.IDENTITY, identityMembershipOrg.identity.id, identityMembershipOrg.scopeOrgId, @@ -419,7 +416,7 @@ export const identityTlsCertAuthServiceFactory = ({ actorOrgId ); - const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId); + const shouldUseNewPrivilegeSystem = Boolean(memberships?.[0]?.shouldUseNewPrivilegeSystem); const permissionBoundary = validatePrivilegeChangeOperation( shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.RevokeAuth, diff --git a/backend/src/services/identity/identity-org-dal.ts b/backend/src/services/identity/identity-org-dal.ts index 956008b12..65aee561c 100644 --- a/backend/src/services/identity/identity-org-dal.ts +++ b/backend/src/services/identity/identity-org-dal.ts @@ -404,7 +404,7 @@ export const identityOrgDALFactory = (db: TDbClient) => { .leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`) .orderBy( orderBy === OrgIdentityOrderBy.Role - ? `${TableName.Membership}.${orderBy}` + ? `${TableName.MembershipRole}.${orderBy}` : `${TableName.Identity}.${orderBy}`, orderDirection ) diff --git a/backend/src/services/membership-group/membership-group-dal.ts b/backend/src/services/membership-group/membership-group-dal.ts index 35a587dc5..b3c35e46f 100644 --- a/backend/src/services/membership-group/membership-group-dal.ts +++ b/backend/src/services/membership-group/membership-group-dal.ts @@ -45,8 +45,7 @@ export const membershipGroupDALFactory = (db: TDbClient) => { } else if (scopeData.scope === AccessScope.Namespace) { void qb .where(`${TableName.Membership}.scope`, AccessScope.Namespace) - .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId) - .whereNull(`${TableName.Membership}.scopeNamespaceId`); + .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId); } else if (scopeData.scope === AccessScope.Project) { void qb .where(`${TableName.Membership}.scope`, AccessScope.Project) @@ -148,8 +147,7 @@ export const membershipGroupDALFactory = (db: TDbClient) => { } else if (scopeData.scope === AccessScope.Namespace) { void qb .where(`${TableName.Membership}.scope`, AccessScope.Namespace) - .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId) - .whereNull(`${TableName.Membership}.scopeNamespaceId`); + .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId); } else if (scopeData.scope === AccessScope.Project) { void qb .where(`${TableName.Membership}.scope`, AccessScope.Project) diff --git a/backend/src/services/membership-group/membership-group-service.ts b/backend/src/services/membership-group/membership-group-service.ts index ec1d1efac..18f6b3ad1 100644 --- a/backend/src/services/membership-group/membership-group-service.ts +++ b/backend/src/services/membership-group/membership-group-service.ts @@ -57,7 +57,7 @@ export const membershipGroupServiceFactory = ({ const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); if (hasNoPermanentRole) { throw new BadRequestError({ - message: "Group must have atleast one permanent role" + message: "Group must have at least one permanent role" }); } const isInvalidTemporaryRole = data.roles.some((el) => { @@ -151,7 +151,7 @@ export const membershipGroupServiceFactory = ({ const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); if (hasNoPermanentRole) { throw new BadRequestError({ - message: "Group must have atleast one permanent role" + message: "Group must have at least one permanent role" }); } const isInvalidTemporaryRole = data.roles.some((el) => { diff --git a/backend/src/services/membership-group/org/org-membership-group-factory.ts b/backend/src/services/membership-group/org/org-membership-group-factory.ts index fe6030c8e..1e87ee3ca 100644 --- a/backend/src/services/membership-group/org/org-membership-group-factory.ts +++ b/backend/src/services/membership-group/org/org-membership-group-factory.ts @@ -84,7 +84,7 @@ export const newOrgMembershipGroupFactory = ({ const onDeleteMembershipGroupGuard: TMembershipGroupScopeFactory["onDeleteMembershipGroupGuard"] = async () => { throw new BadRequestError({ - message: "Organization membership cannot be created for organization scoped group" + message: "Organization membership cannot be deleted for organization scoped group" }); }; diff --git a/backend/src/services/membership-group/project/project-membership-group-factory.ts b/backend/src/services/membership-group/project/project-membership-group-factory.ts index 6900e3755..5a63eed1e 100644 --- a/backend/src/services/membership-group/project/project-membership-group-factory.ts +++ b/backend/src/services/membership-group/project/project-membership-group-factory.ts @@ -120,7 +120,7 @@ export const newProjectMembershipGroupFactory = ({ if (!permissionBoundary.isValid) throw new PermissionBoundaryError({ message: constructPermissionErrorMessage( - "Failed to create group project membership", + "Failed to update group project membership", shouldUseNewPrivilegeSystem, ProjectPermissionGroupActions.GrantPrivileges, ProjectPermissionSub.Groups diff --git a/backend/src/services/membership-identity/membership-identity-dal.ts b/backend/src/services/membership-identity/membership-identity-dal.ts index 3f895f82a..64e508fb8 100644 --- a/backend/src/services/membership-identity/membership-identity-dal.ts +++ b/backend/src/services/membership-identity/membership-identity-dal.ts @@ -52,8 +52,7 @@ export const membershipIdentityDALFactory = (db: TDbClient) => { } else if (scopeData.scope === AccessScope.Namespace) { void qb .where(`${TableName.Membership}.scope`, AccessScope.Namespace) - .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId) - .whereNull(`${TableName.Membership}.scopeNamespaceId`); + .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId); } else if (scopeData.scope === AccessScope.Project) { void qb .where(`${TableName.Membership}.scope`, AccessScope.Project) @@ -236,8 +235,7 @@ export const membershipIdentityDALFactory = (db: TDbClient) => { } else if (scopeData.scope === AccessScope.Namespace) { void qb .where(`${TableName.Membership}.scope`, AccessScope.Namespace) - .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId) - .whereNull(`${TableName.Membership}.scopeNamespaceId`); + .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId); } else if (scopeData.scope === AccessScope.Project) { void qb .where(`${TableName.Membership}.scope`, AccessScope.Project) diff --git a/backend/src/services/membership-identity/membership-identity-service.ts b/backend/src/services/membership-identity/membership-identity-service.ts index 562b751e0..4dd3da064 100644 --- a/backend/src/services/membership-identity/membership-identity-service.ts +++ b/backend/src/services/membership-identity/membership-identity-service.ts @@ -63,7 +63,7 @@ export const membershipIdentityServiceFactory = ({ const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); if (hasNoPermanentRole) { throw new BadRequestError({ - message: "Identity must have atleast one permanent role" + message: "Identity must have at least one permanent role" }); } const isInvalidTemporaryRole = data.roles.some((el) => { @@ -157,7 +157,7 @@ export const membershipIdentityServiceFactory = ({ const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); if (hasNoPermanentRole) { throw new BadRequestError({ - message: "Identity must have atleast one permanent role" + message: "Identity must have at least one permanent role" }); } const isInvalidTemporaryRole = data.roles.some((el) => { diff --git a/backend/src/services/membership-identity/namespace/namespace-membership-identity-factory.ts b/backend/src/services/membership-identity/namespace/namespace-membership-identity-factory.ts index 55656778e..be3ca6ea9 100644 --- a/backend/src/services/membership-identity/namespace/namespace-membership-identity-factory.ts +++ b/backend/src/services/membership-identity/namespace/namespace-membership-identity-factory.ts @@ -24,31 +24,31 @@ export const newNamespaceMembershipIdentityFactory = ( }; const isCustomRole: TMembershipIdentityScopeFactory["isCustomRole"] = () => { - throw new InternalServerError({ message: "Namespace membership user isCustomRole not implemented" }); + throw new InternalServerError({ message: "Namespace membership identity isCustomRole not implemented" }); }; const onCreateMembershipIdentityGuard: TMembershipIdentityScopeFactory["onCreateMembershipIdentityGuard"] = async () => { - throw new InternalServerError({ message: "Namespace membership user create not implemented" }); + throw new InternalServerError({ message: "Namespace membership identity create not implemented" }); }; const onUpdateMembershipIdentityGuard: TMembershipIdentityScopeFactory["onUpdateMembershipIdentityGuard"] = async () => { - throw new InternalServerError({ message: "Namespace membership user update not implemented" }); + throw new InternalServerError({ message: "Namespace membership identity update not implemented" }); }; const onDeleteMembershipIdentityGuard: TMembershipIdentityScopeFactory["onDeleteMembershipIdentityGuard"] = async () => { - throw new InternalServerError({ message: "Namespace membership user delete not implemented" }); + throw new InternalServerError({ message: "Namespace membership identity delete not implemented" }); }; const onListMembershipIdentityGuard: TMembershipIdentityScopeFactory["onListMembershipIdentityGuard"] = async () => { - throw new InternalServerError({ message: "Namespace membership user list not implemented" }); + throw new InternalServerError({ message: "Namespace membership identity list not implemented" }); }; const onGetMembershipIdentityByIdentityIdGuard: TMembershipIdentityScopeFactory["onGetMembershipIdentityByIdentityIdGuard"] = async () => { - throw new InternalServerError({ message: "Namespace membership user get by user id not implemented" }); + throw new InternalServerError({ message: "Namespace membership identity get by identity id not implemented" }); }; return { diff --git a/backend/src/services/membership-identity/org/org-membership-identity-factory.ts b/backend/src/services/membership-identity/org/org-membership-identity-factory.ts index ddd096b59..06789e274 100644 --- a/backend/src/services/membership-identity/org/org-membership-identity-factory.ts +++ b/backend/src/services/membership-identity/org/org-membership-identity-factory.ts @@ -74,7 +74,7 @@ export const newOrgMembershipIdentityFactory = ({ if (!permissionBoundary.isValid) throw new PermissionBoundaryError({ message: constructPermissionErrorMessage( - "Failed to create identity org membership", + "Failed to update identity org membership", shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.GrantPrivileges, OrgPermissionSubjects.Identity @@ -88,7 +88,7 @@ export const newOrgMembershipIdentityFactory = ({ const onDeleteMembershipIdentityGuard: TMembershipIdentityScopeFactory["onDeleteMembershipIdentityGuard"] = async () => { throw new BadRequestError({ - message: "Organization membership cannot be created for organization scoped identity" + message: "Organization membership cannot be deleted for organization scoped identity" }); }; diff --git a/backend/src/services/membership-identity/project/project-membership-identity-factory.ts b/backend/src/services/membership-identity/project/project-membership-identity-factory.ts index 76be11085..f2896047f 100644 --- a/backend/src/services/membership-identity/project/project-membership-identity-factory.ts +++ b/backend/src/services/membership-identity/project/project-membership-identity-factory.ts @@ -129,7 +129,7 @@ export const newProjectMembershipIdentityFactory = ({ if (!permissionBoundary.isValid) throw new PermissionBoundaryError({ message: constructPermissionErrorMessage( - "Failed to create identity project membership", + "Failed to update identity project membership", shouldUseNewPrivilegeSystem, ProjectPermissionIdentityActions.GrantPrivileges, ProjectPermissionSub.Identity diff --git a/backend/src/services/membership-user/membership-user-dal.ts b/backend/src/services/membership-user/membership-user-dal.ts index 864d053b7..7882b9639 100644 --- a/backend/src/services/membership-user/membership-user-dal.ts +++ b/backend/src/services/membership-user/membership-user-dal.ts @@ -51,8 +51,7 @@ export const membershipUserDALFactory = (db: TDbClient) => { } else if (scopeData.scope === AccessScope.Namespace) { void qb .where(`${TableName.Membership}.scope`, AccessScope.Namespace) - .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId) - .whereNull(`${TableName.Membership}.scopeNamespaceId`); + .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId); } else if (scopeData.scope === AccessScope.Project) { void qb .where(`${TableName.Membership}.scope`, AccessScope.Project) @@ -168,8 +167,7 @@ export const membershipUserDALFactory = (db: TDbClient) => { } else if (scopeData.scope === AccessScope.Namespace) { void qb .where(`${TableName.Membership}.scope`, AccessScope.Namespace) - .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId) - .whereNull(`${TableName.Membership}.scopeNamespaceId`); + .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId); } else if (scopeData.scope === AccessScope.Project) { void qb .where(`${TableName.Membership}.scope`, AccessScope.Project) @@ -192,7 +190,7 @@ export const membershipUserDALFactory = (db: TDbClient) => { case "role": return [`${TableName.Role}.slug`, `${TableName.MembershipRole}.role`]; case "username": - return `${TableName.Users}.name`; + return `${TableName.Users}.username`; default: throw new BadRequestError({ message: `Invalid ${String(attr)} provided` }); } diff --git a/backend/src/services/membership-user/membership-user-service.ts b/backend/src/services/membership-user/membership-user-service.ts index 937d79203..82dca0159 100644 --- a/backend/src/services/membership-user/membership-user-service.ts +++ b/backend/src/services/membership-user/membership-user-service.ts @@ -131,13 +131,13 @@ export const membershipUserServiceFactory = ({ existingUsers.push(inviteeUser); const inviteeUserId = inviteeUser?.id; - const existingEncrytionKey = await userDAL.findUserEncKeyByUserId(inviteeUserId, tx); + const existingEncryptionKey = await userDAL.findUserEncKeyByUserId(inviteeUserId, tx); // when user is missing the encrytion keys // this could happen either if user doesn't exist or user didn't find step 3 of generating the encryption keys of srp // So what we do is we generate a random secure password and then encrypt it with a random pub-private key // Then when user sign in (as login is not possible as isAccepted is false) we rencrypt the private key with the user password - if (!inviteeUser || (inviteeUser && !inviteeUser?.isAccepted && !existingEncrytionKey)) { + if (!inviteeUser || (inviteeUser && !inviteeUser?.isAccepted && !existingEncryptionKey)) { await userDAL.createUserEncryption( { userId: inviteeUserId, @@ -159,7 +159,7 @@ export const membershipUserServiceFactory = ({ const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); if (hasNoPermanentRole) { throw new BadRequestError({ - message: "User must have atleast one permanent role" + message: "User must have at least one permanent role" }); } const isInvalidTemporaryRole = data.roles.some((el) => { @@ -284,7 +284,7 @@ export const membershipUserServiceFactory = ({ const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); if (hasNoPermanentRole) { throw new BadRequestError({ - message: "User must have atleast one permanent role" + message: "User must have at least one permanent role" }); } const isInvalidTemporaryRole = data.roles.some((el) => { diff --git a/backend/src/services/org-membership/org-membership-dal.ts b/backend/src/services/org-membership/org-membership-dal.ts index 04a381eaa..c52c2834a 100644 --- a/backend/src/services/org-membership/org-membership-dal.ts +++ b/backend/src/services/org-membership/org-membership-dal.ts @@ -15,6 +15,7 @@ export const orgMembershipDALFactory = (db: TDbClient) => { .whereNotNull(`${TableName.Membership}.actorUserId`) .join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`) .join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`) + .leftJoin(TableName.Role, `${TableName.Role}.id`, `${TableName.MembershipRole}.customRoleId`) .leftJoin( TableName.UserEncryptionKey, `${TableName.UserEncryptionKey}.userId`, @@ -31,6 +32,7 @@ export const orgMembershipDALFactory = (db: TDbClient) => { db.ref("scopeOrgId").withSchema(TableName.Membership).as("orgId"), db.ref("role").withSchema(TableName.MembershipRole), db.ref("customRoleId").withSchema(TableName.MembershipRole).as("roleId"), + db.ref("slug").withSchema(TableName.Role).as("customRoleSlug"), db.ref("status").withSchema(TableName.Membership), db.ref("isActive").withSchema(TableName.Membership), db.ref("lastLoginAuthMethod").withSchema(TableName.Membership), @@ -56,6 +58,7 @@ export const orgMembershipDALFactory = (db: TDbClient) => { parentMapper: ({ email, isEmailVerified, + customRoleSlug, username, firstName, lastName, @@ -75,6 +78,7 @@ export const orgMembershipDALFactory = (db: TDbClient) => { orgId, id, role, + customRoleSlug, status, isActive, inviteEmail, diff --git a/backend/src/services/org/org-dal.ts b/backend/src/services/org/org-dal.ts index 9fa0be700..288926f90 100644 --- a/backend/src/services/org/org-dal.ts +++ b/backend/src/services/org/org-dal.ts @@ -646,7 +646,7 @@ export const orgDALFactory = (db: TDbClient) => { .replicaNode()(TableName.Membership) .where({ actorIdentityId: identityId }) .where(`${TableName.Membership}.scope`, AccessScope.Organization) - .whereNotNull(`${TableName.Membership}.actorUserId`) + .whereNotNull(`${TableName.Membership}.actorIdentityId`) .join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`) .join(TableName.Organization, `${TableName.Membership}.scopeOrgId`, `${TableName.Organization}.id`) .select(db.ref("id").withSchema(TableName.Organization).as("id")) diff --git a/backend/src/services/project-key/project-key-dal.ts b/backend/src/services/project-key/project-key-dal.ts index 0c3a0b72f..07d061e95 100644 --- a/backend/src/services/project-key/project-key-dal.ts +++ b/backend/src/services/project-key/project-key-dal.ts @@ -35,11 +35,11 @@ export const projectKeyDALFactory = (db: TDbClient) => { const findAllProjectUserPubKeys = async (projectId: string, tx?: Knex) => { try { const pubKeys = await (tx || db.replicaNode())(TableName.Membership) - .where(`${TableName.Membership}.scopeProjectId` as "projectId", projectId) + .where(`${TableName.Membership}.scopeProjectId` as "scopeProjectId", projectId) .where(`${TableName.Membership}.scope`, AccessScope.Project) .join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`) .join(TableName.UserEncryptionKey, `${TableName.Users}.id`, `${TableName.UserEncryptionKey}.userId`) - .select("userId", "publicKey"); + .select(db.ref("userId").withSchema(TableName.Users), "publicKey"); return pubKeys; } catch (error) { throw new DatabaseError({ error, name: "Find all workspace pub keys" }); diff --git a/backend/src/services/project-membership/project-membership-dal.ts b/backend/src/services/project-membership/project-membership-dal.ts index be1b94ba1..fe3b57226 100644 --- a/backend/src/services/project-membership/project-membership-dal.ts +++ b/backend/src/services/project-membership/project-membership-dal.ts @@ -42,12 +42,7 @@ export const projectMembershipDALFactory = (db: TDbClient) => { .select("role") .from(TableName.MembershipRole) .leftJoin(TableName.Role, `${TableName.Role}.id`, `${TableName.MembershipRole}.customRoleId`) - .whereRaw("??.?? = ??.??", [ - TableName.MembershipRole, - "projectMembershipId", - TableName.Membership, - "id" - ]) + .whereRaw("??.?? = ??.??", [TableName.MembershipRole, "membershipId", TableName.Membership, "id"]) .where((subQb) => { void subQb .whereIn(`${TableName.MembershipRole}.role`, filter.roles as string[]) diff --git a/backend/src/services/project/project-dal.ts b/backend/src/services/project/project-dal.ts index b3929e530..2abdebdbc 100644 --- a/backend/src/services/project/project-dal.ts +++ b/backend/src/services/project/project-dal.ts @@ -31,7 +31,6 @@ export const projectDALFactory = (db: TDbClient) => { .where(`${TableName.Membership}.actorIdentityId`, identityId) .join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`) .where(`${TableName.Project}.orgId`, orgId) - .join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`) .andWhere((qb) => { if (projectType) { void qb.where(`${TableName.Project}.type`, projectType); diff --git a/backend/src/services/role/role-service.ts b/backend/src/services/role/role-service.ts index 6aaf6cf52..41c825b2e 100644 --- a/backend/src/services/role/role-service.ts +++ b/backend/src/services/role/role-service.ts @@ -72,7 +72,7 @@ export const roleServiceFactory = ({ slug: data.slug, [scope.key]: scope.value }); - if (existingRole) throw new NotFoundError({ message: `Role with ${data.slug} exist` }); + if (existingRole) throw new NotFoundError({ message: `Role with ${data.slug} exists` }); validateHandlebarTemplate("Role Creation", JSON.stringify(data.permissions || []), { allowedExpressions: (val) => val.includes("identity.") @@ -108,7 +108,7 @@ export const roleServiceFactory = ({ [scope.key]: scope.value }); if (existingSlug && existingRole.id !== existingSlug.id) - throw new BadRequestError({ message: `Role with ${data.slug} not found` }); + throw new BadRequestError({ message: `Role with ${data.slug} already exists` }); } validateHandlebarTemplate("Role Update", JSON.stringify(data.permissions || []), { diff --git a/backend/src/services/super-admin/super-admin-service.ts b/backend/src/services/super-admin/super-admin-service.ts index c7ba673eb..904ad4d2e 100644 --- a/backend/src/services/super-admin/super-admin-service.ts +++ b/backend/src/services/super-admin/super-admin-service.ts @@ -597,7 +597,7 @@ export const superAdminServiceFactory = ({ { actorIdentityId: newIdentity.id, scopeOrgId: organization.id, - scope: AccessScope.Project + scope: AccessScope.Organization }, tx ); @@ -947,6 +947,9 @@ export const superAdminServiceFactory = ({ } const membershipRole = await membershipRoleDAL.findOne({ membershipId }); + if (!membershipRole) { + throw new NotFoundError({ name: "Membership Role", message: "Membership role not found" }); + } const [organizationMembership] = await membershipUserDAL.delete({ scopeOrgId: organizationId, scope: AccessScope.Organization, diff --git a/frontend/src/hooks/api/users/types.ts b/frontend/src/hooks/api/users/types.ts index c48b1037b..d313efd23 100644 --- a/frontend/src/hooks/api/users/types.ts +++ b/frontend/src/hooks/api/users/types.ts @@ -64,6 +64,7 @@ export type OrgUser = { inviteEmail: string; organization: string; role: "owner" | "admin" | "member" | "no-access" | "custom"; + customRoleSlug?: string; status: "invited" | "accepted" | "verified" | "completed"; deniedPermissions: any[]; roleId: string; diff --git a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthTemplatesTable.tsx b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthTemplatesTable.tsx index c9993aba8..517fc7823 100644 --- a/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthTemplatesTable.tsx +++ b/frontend/src/pages/organization/AccessManagementPage/components/OrgIdentityTab/components/IdentitySection/IdentityAuthTemplatesTable.tsx @@ -272,7 +272,7 @@ export const IdentityAuthTemplatesTable = ({ handlePopUpOpen }: Props) => { /> )} {!subscription.machineIdentityAuthTemplates && ( - + )} {!isPending && templates.length === 0 && ( { onClick={() => { handlePopUpOpen("selectImportPlatform"); }} - isDisabled={hasOrgRole(OrgMembershipRole.Admin)} + isDisabled={!hasOrgRole(OrgMembershipRole.Admin)} leftIcon={} > Import diff --git a/frontend/src/pages/organization/UserDetailsByIDPage/components/UserDetailsSection.tsx b/frontend/src/pages/organization/UserDetailsByIDPage/components/UserDetailsSection.tsx index 6d3d7e1ae..97b3c0e3c 100644 --- a/frontend/src/pages/organization/UserDetailsByIDPage/components/UserDetailsSection.tsx +++ b/frontend/src/pages/organization/UserDetailsByIDPage/components/UserDetailsSection.tsx @@ -76,7 +76,9 @@ export const UserDetailsSection = ({ membershipId, handlePopUpOpen }: Props) => return m.status === "invited" ? "Invited" : "Active"; }; - const roleName = roles?.find((r) => r.slug === membership?.role)?.name; + const roleName = roles?.find( + (r) => r.slug === membership?.role || r.slug === membership?.customRoleSlug + )?.name; return membership ? (