feat: go greppy

This commit is contained in:
=
2025-10-10 00:09:48 +05:30
parent fe1bc168f6
commit 97135d9cfa
46 changed files with 150 additions and 106 deletions
@@ -665,7 +665,7 @@ export async function up(knex: Knex): Promise<void> {
await createAdditionalPrivilegeTable(knex); await createAdditionalPrivilegeTable(knex);
} }
// no mean this has been created before // this means these tables have been created before
if (hasToMigrateMembershipTable) { if (hasToMigrateMembershipTable) {
await migrateMembershipData(knex); await migrateMembershipData(knex);
} }
@@ -784,7 +784,6 @@ const rollbackMembershipRoleData = async (knex: Knex) => {
knex(TableName.MembershipRole) knex(TableName.MembershipRole)
.join(TableName.Membership, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`) .join(TableName.Membership, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`)
.join(TableName.Groups, `${TableName.Membership}.actorGroupId`, `${TableName.Groups}.id`) .join(TableName.Groups, `${TableName.Membership}.actorGroupId`, `${TableName.Groups}.id`)
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
.whereNotNull(`${TableName.Membership}.actorGroupId`) .whereNotNull(`${TableName.Membership}.actorGroupId`)
.where(`${TableName.Membership}.scope`, AccessScope.Organization) .where(`${TableName.Membership}.scope`, AccessScope.Organization)
.select( .select(
@@ -281,7 +281,6 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
}, },
data: { data: {
...req.body, ...req.body,
isTemporary: true,
...updatedInfo, ...updatedInfo,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore-error this is valid ts // @ts-ignore-error this is valid ts
@@ -6,13 +6,15 @@ import { paginateGraphql } from "@octokit/plugin-paginate-graphql";
import { Octokit as OctokitRest } from "@octokit/rest"; import { Octokit as OctokitRest } from "@octokit/rest";
import RE2 from "re2"; 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 { BadRequestError, NotFoundError } from "@app/lib/errors";
import { groupBy } from "@app/lib/fn"; import { groupBy } from "@app/lib/fn";
import { logger } from "@app/lib/logger"; import { logger } from "@app/lib/logger";
import { retryWithBackoff } from "@app/lib/retry"; import { retryWithBackoff } from "@app/lib/retry";
import { TKmsServiceFactory } from "@app/services/kms/kms-service"; import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { KmsDataKey } from "@app/services/kms/kms-types"; 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 { TOrgMembershipDALFactory } from "@app/services/org-membership/org-membership-dal";
import { TGroupDALFactory } from "../group/group-dal"; import { TGroupDALFactory } from "../group/group-dal";
@@ -77,6 +79,8 @@ type TGithubOrgSyncServiceFactoryDep = {
"findGroupMembershipsByUserIdInOrg" | "findGroupMembershipsByGroupIdInOrg" | "insertMany" | "delete" "findGroupMembershipsByUserIdInOrg" | "findGroupMembershipsByGroupIdInOrg" | "insertMany" | "delete"
>; >;
groupDAL: Pick<TGroupDALFactory, "insertMany" | "transaction" | "find">; groupDAL: Pick<TGroupDALFactory, "insertMany" | "transaction" | "find">;
membershipRoleDAL: Pick<TMembershipRoleDALFactory, "insertMany">;
membershipGroupDAL: Pick<TMembershipGroupDALFactory, "insertMany">;
licenseService: Pick<TLicenseServiceFactory, "getPlan">; licenseService: Pick<TLicenseServiceFactory, "getPlan">;
orgMembershipDAL: Pick<TOrgMembershipDALFactory, "findOrgMembershipById" | "findOrgMembershipsWithUsersByOrgId">; orgMembershipDAL: Pick<TOrgMembershipDALFactory, "findOrgMembershipById" | "findOrgMembershipsWithUsersByOrgId">;
}; };
@@ -90,7 +94,9 @@ export const githubOrgSyncServiceFactory = ({
userGroupMembershipDAL, userGroupMembershipDAL,
groupDAL, groupDAL,
licenseService, licenseService,
orgMembershipDAL orgMembershipDAL,
membershipRoleDAL,
membershipGroupDAL
}: TGithubOrgSyncServiceFactoryDep) => { }: TGithubOrgSyncServiceFactoryDep) => {
const createGithubOrgSync = async ({ const createGithubOrgSync = async ({
githubOrgName, githubOrgName,
@@ -365,6 +371,25 @@ export const githubOrgSyncServiceFactory = ({
})), })),
tx 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( await userGroupMembershipDAL.insertMany(
newGroups.map((el) => ({ newGroups.map((el) => ({
groupId: el.id, groupId: el.id,
@@ -691,6 +716,25 @@ export const githubOrgSyncServiceFactory = ({
tx 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) => { newGroups.forEach((group) => {
if (!existingTeamsMap[group.name]) { if (!existingTeamsMap[group.name]) {
existingTeamsMap[group.name] = []; existingTeamsMap[group.name] = [];
@@ -71,7 +71,7 @@ export const userGroupMembershipDALFactory = (db: TDbClient) => {
const groups: string[] = await (tx || db.replicaNode())(TableName.Membership) const groups: string[] = await (tx || db.replicaNode())(TableName.Membership)
.where(`${TableName.Membership}.scopeProjectId`, projectId) .where(`${TableName.Membership}.scopeProjectId`, projectId)
.whereNot(`${TableName.Membership}.actorGroupId`, groupId) .whereNot(`${TableName.Membership}.actorGroupId`, groupId)
.pluck(`${TableName.Membership}.groupId`); .pluck(`${TableName.Membership}.actorGroupId`);
// main query // main query
const members = await (tx || db.replicaNode())(TableName.UserGroupMembership) const members = await (tx || db.replicaNode())(TableName.UserGroupMembership)
@@ -36,7 +36,7 @@ export const licenseDALFactory = (db: TDbClient) => {
void bd.where(`${TableName.Membership}.scopeOrgId`, orgId); 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) .where(`${TableName.Users}.isGhost`, false)
.count(); .count();
@@ -219,7 +219,9 @@ export const OrgPermissionSchema = z.discriminatedUnion("subject", [
}), }),
z.object({ z.object({
subject: z.literal(OrgPermissionSubjects.Groups).describe("The entity this permission pertains to."), 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({ z.object({
subject: z.literal(OrgPermissionSubjects.SecretScanning).describe("The entity this permission pertains to."), subject: z.literal(OrgPermissionSubjects.SecretScanning).describe("The entity this permission pertains to."),
@@ -231,7 +233,9 @@ export const OrgPermissionSchema = z.discriminatedUnion("subject", [
}), }),
z.object({ z.object({
subject: z.literal(OrgPermissionSubjects.Identity).describe("The entity this permission pertains to."), 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({ z.object({
subject: z.literal(OrgPermissionSubjects.Kms).describe("The entity this permission pertains to."), subject: z.literal(OrgPermissionSubjects.Kms).describe("The entity this permission pertains to."),
@@ -18,6 +18,7 @@ import { ActorType } from "@app/services/auth/auth-type";
interface TPermissionDataReturn extends TMemberships { interface TPermissionDataReturn extends TMemberships {
orgAuthEnforced?: boolean | null; orgAuthEnforced?: boolean | null;
orgGoogleSsoAuthEnforced?: boolean | null; orgGoogleSsoAuthEnforced?: boolean | null;
shouldUseNewPrivilegeSystem?: boolean | null;
bypassOrgAuthEnabled?: boolean | null; bypassOrgAuthEnabled?: boolean | null;
roles: { roles: {
id: string; id: string;
@@ -223,8 +224,7 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => {
} else if (scopeData.scope === AccessScope.Namespace) { } else if (scopeData.scope === AccessScope.Namespace) {
void qb void qb
.where(`${TableName.Membership}.scope`, AccessScope.Namespace) .where(`${TableName.Membership}.scope`, AccessScope.Namespace)
.where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId) .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId);
.whereNull(`${TableName.Membership}.scopeNamespaceId`);
} else if (scopeData.scope === AccessScope.Project) { } else if (scopeData.scope === AccessScope.Project) {
void qb void qb
.where(`${TableName.Membership}.scope`, AccessScope.Project) .where(`${TableName.Membership}.scope`, AccessScope.Project)
@@ -282,6 +282,7 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => {
parentMapper: (el) => parentMapper: (el) =>
MembershipsSchema.extend({ MembershipsSchema.extend({
orgAuthEnforced: z.boolean().optional().nullable(), orgAuthEnforced: z.boolean().optional().nullable(),
shouldUseNewPrivilegeSystem: z.boolean().optional().nullable(),
orgGoogleSsoAuthEnforced: z.boolean(), orgGoogleSsoAuthEnforced: z.boolean(),
bypassOrgAuthEnabled: z.boolean() bypassOrgAuthEnabled: z.boolean()
}).parse(el), }).parse(el),
@@ -66,7 +66,12 @@ export type TPermissionServiceFactory = {
actorOrgId: string | undefined actorOrgId: string | undefined
) => Promise<{ ) => Promise<{
permission: MongoAbility<OrgPermissionSet, MongoQuery>; permission: MongoAbility<OrgPermissionSet, MongoQuery>;
memberships: Array<TMemberships & { roles: { role: string; customRoleSlug?: string | null }[] }>; memberships: Array<
TMemberships & {
roles: { role: string; customRoleSlug?: string | null }[];
shouldUseNewPrivilegeSystem?: boolean | null;
}
>;
hasRole: (role: string) => boolean; hasRole: (role: string) => boolean;
}>; }>;
getProjectPermission: (arg: TGetProjectPermissionArg) => Promise<{ getProjectPermission: (arg: TGetProjectPermissionArg) => Promise<{
@@ -258,10 +258,6 @@ export const permissionServiceFactory = ({
if (!serviceTokenProject) throw new BadRequestError({ message: "Service token not linked to a project" }); 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) { if (serviceToken.projectId !== projectId) {
throw new ForbiddenRequestError({ throw new ForbiddenRequestError({
name: `Service token not a part of the specified project with ID ${projectId}` name: `Service token not a part of the specified project with ID ${projectId}`
+8 -5
View File
@@ -354,11 +354,14 @@ export const scimServiceFactory = ({
}, },
tx tx
); );
await membershipRoleDAL.create({ await membershipRoleDAL.create(
membershipId: orgMembership.id, {
role, membershipId: orgMembership.id,
customRoleId: roleId role,
}); customRoleId: roleId
},
tx
);
} else if (orgMembership.status === OrgMembershipStatus.Invited && user.isAccepted) { } else if (orgMembership.status === OrgMembershipStatus.Invited && user.isAccepted) {
orgMembership = await membershipUserDAL.updateById( orgMembership = await membershipUserDAL.updateById(
orgMembership.id, orgMembership.id,
@@ -37,6 +37,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
.where(filter) .where(filter)
.join(TableName.SecretFolder, `${TableName.SecretApprovalRequest}.folderId`, `${TableName.SecretFolder}.id`) .join(TableName.SecretFolder, `${TableName.SecretApprovalRequest}.folderId`, `${TableName.SecretFolder}.id`)
.join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`) .join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`)
.join(TableName.Project, `${TableName.Environment}.projectId`, `${TableName.Project}.id`)
.join( .join(
TableName.SecretApprovalPolicy, TableName.SecretApprovalPolicy,
`${TableName.SecretApprovalRequest}.policyId`, `${TableName.SecretApprovalRequest}.policyId`,
@@ -111,24 +112,20 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => {
) )
.leftJoin<TMemberships>(db(TableName.Membership).as("approverOrgMembership"), (qb) => { .leftJoin<TMemberships>(db(TableName.Membership).as("approverOrgMembership"), (qb) => {
qb.on(`${TableName.SecretApprovalPolicyApprover}.approverUserId`, `approverOrgMembership.actorUserId`).andOn( qb.on(`${TableName.SecretApprovalPolicyApprover}.approverUserId`, `approverOrgMembership.actorUserId`)
`approverOrgMembership.scope`, .andOn(`approverOrgMembership.scopeOrgId`, `${TableName.Project}.orgId`)
db.raw("?", [AccessScope.Organization]) .andOn(`approverOrgMembership.scope`, db.raw("?", [AccessScope.Organization]));
);
}) })
.leftJoin<TMemberships>(db(TableName.Membership).as("approverGroupOrgMembership"), (qb) => { .leftJoin<TMemberships>(db(TableName.Membership).as("approverGroupOrgMembership"), (qb) => {
qb.on(`secretApprovalPolicyGroupApproverUser.id`, `approverGroupOrgMembership.actorUserId`).andOn( qb.on(`secretApprovalPolicyGroupApproverUser.id`, `approverGroupOrgMembership.actorUserId`)
`approverGroupOrgMembership.scope`, .andOn(`approverGroupOrgMembership.scopeOrgId`, `${TableName.Project}.orgId`)
db.raw("?", [AccessScope.Organization]) .andOn(`approverGroupOrgMembership.scope`, db.raw("?", [AccessScope.Organization]));
);
}) })
.leftJoin<TMemberships>(db(TableName.Membership).as("reviewerOrgMembership"), (qb) => { .leftJoin<TMemberships>(db(TableName.Membership).as("reviewerOrgMembership"), (qb) => {
qb.on(`${TableName.SecretApprovalRequestReviewer}.reviewerUserId`, `reviewerOrgMembership.actorUserId`).andOn( qb.on(`${TableName.SecretApprovalRequestReviewer}.reviewerUserId`, `reviewerOrgMembership.actorUserId`)
`reviewerOrgMembership.scope`, .andOn(`reviewerOrgMembership.scopeOrgId`, `${TableName.Project}.orgId`)
db.raw("?", [AccessScope.Organization]) .andOn(`reviewerOrgMembership.scope`, db.raw("?", [AccessScope.Organization]));
);
}) })
.select(selectAllTableCols(TableName.SecretApprovalRequest)) .select(selectAllTableCols(TableName.SecretApprovalRequest))
.select( .select(
+3 -2
View File
@@ -778,7 +778,9 @@ export const registerRoutes = async (
permissionService, permissionService,
groupDAL, groupDAL,
userGroupMembershipDAL, userGroupMembershipDAL,
orgMembershipDAL orgMembershipDAL,
membershipRoleDAL,
membershipGroupDAL
}); });
const ldapService = ldapConfigServiceFactory({ const ldapService = ldapConfigServiceFactory({
@@ -1643,7 +1645,6 @@ export const registerRoutes = async (
const identityTlsCertAuthService = identityTlsCertAuthServiceFactory({ const identityTlsCertAuthService = identityTlsCertAuthServiceFactory({
identityAccessTokenDAL, identityAccessTokenDAL,
orgDAL,
identityTlsCertAuthDAL, identityTlsCertAuthDAL,
licenseService, licenseService,
permissionService, permissionService,
@@ -12,10 +12,10 @@ import {
import { EFilterReturnedUsers } from "@app/ee/services/group/group-types"; import { EFilterReturnedUsers } from "@app/ee/services/group/group-types";
import { ApiDocsTags, GROUPS, PROJECTS } from "@app/lib/api-docs"; import { ApiDocsTags, GROUPS, PROJECTS } from "@app/lib/api-docs";
import { ms } from "@app/lib/ms"; import { ms } from "@app/lib/ms";
import { isUuidV4 } from "@app/lib/validator";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type"; import { AuthMode } from "@app/services/auth/auth-type";
import { isUuidV4 } from "@app/lib/validator";
export const registerGroupProjectRouter = async (server: FastifyZodProvider) => { export const registerGroupProjectRouter = async (server: FastifyZodProvider) => {
server.route({ server.route({
@@ -12,10 +12,10 @@ import {
import { EFilterReturnedUsers } from "@app/ee/services/group/group-types"; import { EFilterReturnedUsers } from "@app/ee/services/group/group-types";
import { ApiDocsTags, GROUPS, PROJECTS } from "@app/lib/api-docs"; import { ApiDocsTags, GROUPS, PROJECTS } from "@app/lib/api-docs";
import { ms } from "@app/lib/ms"; import { ms } from "@app/lib/ms";
import { isUuidV4 } from "@app/lib/validator";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type"; import { AuthMode } from "@app/services/auth/auth-type";
import { isUuidV4 } from "@app/lib/validator";
export const registerDeprecatedGroupProjectRouter = async (server: FastifyZodProvider) => { export const registerDeprecatedGroupProjectRouter = async (server: FastifyZodProvider) => {
server.route({ server.route({
@@ -139,6 +139,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
response: { response: {
200: z.object({ 200: z.object({
membership: OrgMembershipsSchema.extend({ membership: OrgMembershipsSchema.extend({
customRoleSlug: z.string().nullish(),
metadata: z metadata: z
.object({ .object({
key: z.string().trim().min(1), key: z.string().trim().min(1),
@@ -224,7 +225,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
return { return {
membership: { membership: {
...membership, ...membership,
role: "", role: req.body.role || "",
orgId: req.params.organizationId, orgId: req.params.organizationId,
status: membership.status || OrgMembershipStatus.Accepted status: membership.status || OrgMembershipStatus.Accepted
} }
@@ -63,7 +63,7 @@ export const additionalPrivilegeServiceFactory = ({
[dbActorField]: data.actorId, [dbActorField]: data.actorId,
[scope.key]: scope.value [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 || []), { validateHandlebarTemplate("Additional Privilege Create", JSON.stringify(data.permissions || []), {
allowedExpressions: (val) => val.includes("identity.") allowedExpressions: (val) => val.includes("identity.")
@@ -115,12 +115,12 @@ export const additionalPrivilegeServiceFactory = ({
const dbActorField = dto.selector.actorType === ActorType.IDENTITY ? "actorIdentityId" : "actorUserId"; const dbActorField = dto.selector.actorType === ActorType.IDENTITY ? "actorIdentityId" : "actorUserId";
const existingPrivilege = await additionalPrivilegeDAL.findOne({ const existingPrivilege = await additionalPrivilegeDAL.findOne({
id: dto.selector.id,
[dbActorField]: dto.selector.actorId, [dbActorField]: dto.selector.actorId,
id: dto.selector.id,
[scope.key]: scope.value [scope.key]: scope.value
}); });
if (!existingPrivilege) 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 || []), { validateHandlebarTemplate("Additional Privilege Create", JSON.stringify(data.permissions || []), {
allowedExpressions: (val) => val.includes("identity.") allowedExpressions: (val) => val.includes("identity.")
@@ -1,10 +1,10 @@
import { AccessScope } from "@app/db/schemas"; import { AccessScope } from "@app/db/schemas";
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
import { NotFoundError } from "@app/lib/errors"; import { NotFoundError } from "@app/lib/errors";
import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal"; import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal";
import { TMembershipDALFactory } from "../membership/membership-dal"; import { TMembershipDALFactory } from "../membership/membership-dal";
import { TProjectDALFactory } from "../project/project-dal"; import { TProjectDALFactory } from "../project/project-dal";
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
type TConvertorServiceFactoryDep = { type TConvertorServiceFactoryDep = {
projectDAL: Pick<TProjectDALFactory, "findOne">; projectDAL: Pick<TProjectDALFactory, "findOne">;
@@ -105,7 +105,7 @@ export const convertorServiceFactory = ({
projectId projectId
}); });
if (!privilege) { 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 }; return { privilegeId: privilege.id, privilege };
@@ -54,7 +54,7 @@ export const externalMigrationServiceFactory = ({
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId
); );
if (hasRole(OrgMembershipRole.Admin)) { if (!hasRole(OrgMembershipRole.Admin)) {
throw new ForbiddenRequestError({ message: "Only admins can import data" }); throw new ForbiddenRequestError({ message: "Only admins can import data" });
} }
@@ -102,7 +102,7 @@ export const externalMigrationServiceFactory = ({
actorOrgId actorOrgId
); );
if (hasRole(OrgMembershipRole.Admin)) { if (!hasRole(OrgMembershipRole.Admin)) {
throw new ForbiddenRequestError({ message: "Only admins can import data" }); throw new ForbiddenRequestError({ message: "Only admins can import data" });
} }
@@ -158,7 +158,7 @@ export const externalMigrationServiceFactory = ({
actorOrgId actorOrgId
); );
if (hasRole(OrgMembershipRole.Admin)) { if (!hasRole(OrgMembershipRole.Admin)) {
throw new ForbiddenRequestError({ message: "Only admins can check custom migration status" }); throw new ForbiddenRequestError({ message: "Only admins can check custom migration status" });
} }
@@ -29,7 +29,6 @@ export const groupProjectDALFactory = (db: TDbClient) => {
db.ref("id").as("groupId").withSchema(TableName.Groups), db.ref("id").as("groupId").withSchema(TableName.Groups),
db.ref("name").as("groupName").withSchema(TableName.Groups), db.ref("name").as("groupName").withSchema(TableName.Groups),
db.ref("slug").as("groupSlug").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("role").withSchema(TableName.MembershipRole),
db.ref("id").withSchema(TableName.MembershipRole).as("membershipRoleId"), db.ref("id").withSchema(TableName.MembershipRole).as("membershipRoleId"),
db.ref("customRoleId").withSchema(TableName.MembershipRole), db.ref("customRoleId").withSchema(TableName.MembershipRole),
@@ -257,7 +257,7 @@ export const identityOidcAuthServiceFactory = ({
identityId identityId
}); });
if (!identityMembershipOrg) { 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)) { if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OIDC_AUTH)) {
throw new BadRequestError({ throw new BadRequestError({
@@ -429,7 +429,7 @@ export const identityProjectDALFactory = (db: TDbClient) => {
.join(TableName.Identity, `${TableName.Membership}.actorIdentityId`, `${TableName.Identity}.id`) .join(TableName.Identity, `${TableName.Membership}.actorIdentityId`, `${TableName.Identity}.id`)
.where((qb) => { .where((qb) => {
if (filter.identityId) { if (filter.identityId) {
void qb.where("identityId", filter.identityId); void qb.where(`${TableName.Membership}.actorIdentityId`, filter.identityId);
} }
if (filter.search) { if (filter.search) {
@@ -15,7 +15,7 @@ import {
type TIdentityProjectServiceFactoryDep = { type TIdentityProjectServiceFactoryDep = {
identityProjectDAL: TIdentityProjectDALFactory; identityProjectDAL: TIdentityProjectDALFactory;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getProjectPermissionByRoles">; permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
membershipIdentityDAL: TMembershipIdentityDALFactory; membershipIdentityDAL: TMembershipIdentityDALFactory;
}; };
@@ -20,7 +20,6 @@ import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identit
import { TKmsServiceFactory } from "../kms/kms-service"; import { TKmsServiceFactory } from "../kms/kms-service";
import { KmsDataKey } from "../kms/kms-types"; import { KmsDataKey } from "../kms/kms-types";
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal"; import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
import { TOrgDALFactory } from "../org/org-dal";
import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns"; import { validateIdentityUpdateForSuperAdminPrivileges } from "../super-admin/super-admin-fns";
import { TIdentityTlsCertAuthDALFactory } from "./identity-tls-cert-auth-dal"; import { TIdentityTlsCertAuthDALFactory } from "./identity-tls-cert-auth-dal";
import { TIdentityTlsCertAuthServiceFactory } from "./identity-tls-cert-auth-types"; import { TIdentityTlsCertAuthServiceFactory } from "./identity-tls-cert-auth-types";
@@ -35,7 +34,6 @@ type TIdentityTlsCertAuthServiceFactoryDep = {
licenseService: Pick<TLicenseServiceFactory, "getPlan">; licenseService: Pick<TLicenseServiceFactory, "getPlan">;
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">; permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">; kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
orgDAL: Pick<TOrgDALFactory, "findById">;
}; };
const parseSubjectDetails = (data: string) => { const parseSubjectDetails = (data: string) => {
@@ -53,8 +51,7 @@ export const identityTlsCertAuthServiceFactory = ({
membershipIdentityDAL, membershipIdentityDAL,
licenseService, licenseService,
permissionService, permissionService,
kmsService, kmsService
orgDAL
}: TIdentityTlsCertAuthServiceFactoryDep): TIdentityTlsCertAuthServiceFactory => { }: TIdentityTlsCertAuthServiceFactoryDep): TIdentityTlsCertAuthServiceFactory => {
const login: TIdentityTlsCertAuthServiceFactory["login"] = async ({ identityId, clientCertificate }) => { const login: TIdentityTlsCertAuthServiceFactory["login"] = async ({ identityId, clientCertificate }) => {
const identityTlsCertAuth = await identityTlsCertAuthDAL.findOne({ identityId }); const identityTlsCertAuth = await identityTlsCertAuthDAL.findOne({ identityId });
@@ -411,7 +408,7 @@ export const identityTlsCertAuthServiceFactory = ({
); );
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
const { permission: rolePermission } = await permissionService.getOrgPermission( const { permission: rolePermission, memberships } = await permissionService.getOrgPermission(
ActorType.IDENTITY, ActorType.IDENTITY,
identityMembershipOrg.identity.id, identityMembershipOrg.identity.id,
identityMembershipOrg.scopeOrgId, identityMembershipOrg.scopeOrgId,
@@ -419,7 +416,7 @@ export const identityTlsCertAuthServiceFactory = ({
actorOrgId actorOrgId
); );
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId); const shouldUseNewPrivilegeSystem = Boolean(memberships?.[0]?.shouldUseNewPrivilegeSystem);
const permissionBoundary = validatePrivilegeChangeOperation( const permissionBoundary = validatePrivilegeChangeOperation(
shouldUseNewPrivilegeSystem, shouldUseNewPrivilegeSystem,
OrgPermissionIdentityActions.RevokeAuth, OrgPermissionIdentityActions.RevokeAuth,
@@ -404,7 +404,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`) .leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
.orderBy( .orderBy(
orderBy === OrgIdentityOrderBy.Role orderBy === OrgIdentityOrderBy.Role
? `${TableName.Membership}.${orderBy}` ? `${TableName.MembershipRole}.${orderBy}`
: `${TableName.Identity}.${orderBy}`, : `${TableName.Identity}.${orderBy}`,
orderDirection orderDirection
) )
@@ -45,8 +45,7 @@ export const membershipGroupDALFactory = (db: TDbClient) => {
} else if (scopeData.scope === AccessScope.Namespace) { } else if (scopeData.scope === AccessScope.Namespace) {
void qb void qb
.where(`${TableName.Membership}.scope`, AccessScope.Namespace) .where(`${TableName.Membership}.scope`, AccessScope.Namespace)
.where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId) .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId);
.whereNull(`${TableName.Membership}.scopeNamespaceId`);
} else if (scopeData.scope === AccessScope.Project) { } else if (scopeData.scope === AccessScope.Project) {
void qb void qb
.where(`${TableName.Membership}.scope`, AccessScope.Project) .where(`${TableName.Membership}.scope`, AccessScope.Project)
@@ -148,8 +147,7 @@ export const membershipGroupDALFactory = (db: TDbClient) => {
} else if (scopeData.scope === AccessScope.Namespace) { } else if (scopeData.scope === AccessScope.Namespace) {
void qb void qb
.where(`${TableName.Membership}.scope`, AccessScope.Namespace) .where(`${TableName.Membership}.scope`, AccessScope.Namespace)
.where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId) .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId);
.whereNull(`${TableName.Membership}.scopeNamespaceId`);
} else if (scopeData.scope === AccessScope.Project) { } else if (scopeData.scope === AccessScope.Project) {
void qb void qb
.where(`${TableName.Membership}.scope`, AccessScope.Project) .where(`${TableName.Membership}.scope`, AccessScope.Project)
@@ -57,7 +57,7 @@ export const membershipGroupServiceFactory = ({
const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); const hasNoPermanentRole = data.roles.every((el) => el.isTemporary);
if (hasNoPermanentRole) { if (hasNoPermanentRole) {
throw new BadRequestError({ 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) => { const isInvalidTemporaryRole = data.roles.some((el) => {
@@ -151,7 +151,7 @@ export const membershipGroupServiceFactory = ({
const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); const hasNoPermanentRole = data.roles.every((el) => el.isTemporary);
if (hasNoPermanentRole) { if (hasNoPermanentRole) {
throw new BadRequestError({ 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) => { const isInvalidTemporaryRole = data.roles.some((el) => {
@@ -84,7 +84,7 @@ export const newOrgMembershipGroupFactory = ({
const onDeleteMembershipGroupGuard: TMembershipGroupScopeFactory["onDeleteMembershipGroupGuard"] = async () => { const onDeleteMembershipGroupGuard: TMembershipGroupScopeFactory["onDeleteMembershipGroupGuard"] = async () => {
throw new BadRequestError({ throw new BadRequestError({
message: "Organization membership cannot be created for organization scoped group" message: "Organization membership cannot be deleted for organization scoped group"
}); });
}; };
@@ -120,7 +120,7 @@ export const newProjectMembershipGroupFactory = ({
if (!permissionBoundary.isValid) if (!permissionBoundary.isValid)
throw new PermissionBoundaryError({ throw new PermissionBoundaryError({
message: constructPermissionErrorMessage( message: constructPermissionErrorMessage(
"Failed to create group project membership", "Failed to update group project membership",
shouldUseNewPrivilegeSystem, shouldUseNewPrivilegeSystem,
ProjectPermissionGroupActions.GrantPrivileges, ProjectPermissionGroupActions.GrantPrivileges,
ProjectPermissionSub.Groups ProjectPermissionSub.Groups
@@ -52,8 +52,7 @@ export const membershipIdentityDALFactory = (db: TDbClient) => {
} else if (scopeData.scope === AccessScope.Namespace) { } else if (scopeData.scope === AccessScope.Namespace) {
void qb void qb
.where(`${TableName.Membership}.scope`, AccessScope.Namespace) .where(`${TableName.Membership}.scope`, AccessScope.Namespace)
.where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId) .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId);
.whereNull(`${TableName.Membership}.scopeNamespaceId`);
} else if (scopeData.scope === AccessScope.Project) { } else if (scopeData.scope === AccessScope.Project) {
void qb void qb
.where(`${TableName.Membership}.scope`, AccessScope.Project) .where(`${TableName.Membership}.scope`, AccessScope.Project)
@@ -236,8 +235,7 @@ export const membershipIdentityDALFactory = (db: TDbClient) => {
} else if (scopeData.scope === AccessScope.Namespace) { } else if (scopeData.scope === AccessScope.Namespace) {
void qb void qb
.where(`${TableName.Membership}.scope`, AccessScope.Namespace) .where(`${TableName.Membership}.scope`, AccessScope.Namespace)
.where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId) .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId);
.whereNull(`${TableName.Membership}.scopeNamespaceId`);
} else if (scopeData.scope === AccessScope.Project) { } else if (scopeData.scope === AccessScope.Project) {
void qb void qb
.where(`${TableName.Membership}.scope`, AccessScope.Project) .where(`${TableName.Membership}.scope`, AccessScope.Project)
@@ -63,7 +63,7 @@ export const membershipIdentityServiceFactory = ({
const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); const hasNoPermanentRole = data.roles.every((el) => el.isTemporary);
if (hasNoPermanentRole) { if (hasNoPermanentRole) {
throw new BadRequestError({ 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) => { const isInvalidTemporaryRole = data.roles.some((el) => {
@@ -157,7 +157,7 @@ export const membershipIdentityServiceFactory = ({
const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); const hasNoPermanentRole = data.roles.every((el) => el.isTemporary);
if (hasNoPermanentRole) { if (hasNoPermanentRole) {
throw new BadRequestError({ 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) => { const isInvalidTemporaryRole = data.roles.some((el) => {
@@ -24,31 +24,31 @@ export const newNamespaceMembershipIdentityFactory = (
}; };
const isCustomRole: TMembershipIdentityScopeFactory["isCustomRole"] = () => { 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"] = const onCreateMembershipIdentityGuard: TMembershipIdentityScopeFactory["onCreateMembershipIdentityGuard"] =
async () => { 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"] = const onUpdateMembershipIdentityGuard: TMembershipIdentityScopeFactory["onUpdateMembershipIdentityGuard"] =
async () => { 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"] = const onDeleteMembershipIdentityGuard: TMembershipIdentityScopeFactory["onDeleteMembershipIdentityGuard"] =
async () => { 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 () => { 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"] = const onGetMembershipIdentityByIdentityIdGuard: TMembershipIdentityScopeFactory["onGetMembershipIdentityByIdentityIdGuard"] =
async () => { 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 { return {
@@ -74,7 +74,7 @@ export const newOrgMembershipIdentityFactory = ({
if (!permissionBoundary.isValid) if (!permissionBoundary.isValid)
throw new PermissionBoundaryError({ throw new PermissionBoundaryError({
message: constructPermissionErrorMessage( message: constructPermissionErrorMessage(
"Failed to create identity org membership", "Failed to update identity org membership",
shouldUseNewPrivilegeSystem, shouldUseNewPrivilegeSystem,
OrgPermissionIdentityActions.GrantPrivileges, OrgPermissionIdentityActions.GrantPrivileges,
OrgPermissionSubjects.Identity OrgPermissionSubjects.Identity
@@ -88,7 +88,7 @@ export const newOrgMembershipIdentityFactory = ({
const onDeleteMembershipIdentityGuard: TMembershipIdentityScopeFactory["onDeleteMembershipIdentityGuard"] = const onDeleteMembershipIdentityGuard: TMembershipIdentityScopeFactory["onDeleteMembershipIdentityGuard"] =
async () => { async () => {
throw new BadRequestError({ throw new BadRequestError({
message: "Organization membership cannot be created for organization scoped identity" message: "Organization membership cannot be deleted for organization scoped identity"
}); });
}; };
@@ -129,7 +129,7 @@ export const newProjectMembershipIdentityFactory = ({
if (!permissionBoundary.isValid) if (!permissionBoundary.isValid)
throw new PermissionBoundaryError({ throw new PermissionBoundaryError({
message: constructPermissionErrorMessage( message: constructPermissionErrorMessage(
"Failed to create identity project membership", "Failed to update identity project membership",
shouldUseNewPrivilegeSystem, shouldUseNewPrivilegeSystem,
ProjectPermissionIdentityActions.GrantPrivileges, ProjectPermissionIdentityActions.GrantPrivileges,
ProjectPermissionSub.Identity ProjectPermissionSub.Identity
@@ -51,8 +51,7 @@ export const membershipUserDALFactory = (db: TDbClient) => {
} else if (scopeData.scope === AccessScope.Namespace) { } else if (scopeData.scope === AccessScope.Namespace) {
void qb void qb
.where(`${TableName.Membership}.scope`, AccessScope.Namespace) .where(`${TableName.Membership}.scope`, AccessScope.Namespace)
.where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId) .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId);
.whereNull(`${TableName.Membership}.scopeNamespaceId`);
} else if (scopeData.scope === AccessScope.Project) { } else if (scopeData.scope === AccessScope.Project) {
void qb void qb
.where(`${TableName.Membership}.scope`, AccessScope.Project) .where(`${TableName.Membership}.scope`, AccessScope.Project)
@@ -168,8 +167,7 @@ export const membershipUserDALFactory = (db: TDbClient) => {
} else if (scopeData.scope === AccessScope.Namespace) { } else if (scopeData.scope === AccessScope.Namespace) {
void qb void qb
.where(`${TableName.Membership}.scope`, AccessScope.Namespace) .where(`${TableName.Membership}.scope`, AccessScope.Namespace)
.where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId) .where(`${TableName.Membership}.scopeNamespaceId`, scopeData.namespaceId);
.whereNull(`${TableName.Membership}.scopeNamespaceId`);
} else if (scopeData.scope === AccessScope.Project) { } else if (scopeData.scope === AccessScope.Project) {
void qb void qb
.where(`${TableName.Membership}.scope`, AccessScope.Project) .where(`${TableName.Membership}.scope`, AccessScope.Project)
@@ -192,7 +190,7 @@ export const membershipUserDALFactory = (db: TDbClient) => {
case "role": case "role":
return [`${TableName.Role}.slug`, `${TableName.MembershipRole}.role`]; return [`${TableName.Role}.slug`, `${TableName.MembershipRole}.role`];
case "username": case "username":
return `${TableName.Users}.name`; return `${TableName.Users}.username`;
default: default:
throw new BadRequestError({ message: `Invalid ${String(attr)} provided` }); throw new BadRequestError({ message: `Invalid ${String(attr)} provided` });
} }
@@ -131,13 +131,13 @@ export const membershipUserServiceFactory = ({
existingUsers.push(inviteeUser); existingUsers.push(inviteeUser);
const inviteeUserId = inviteeUser?.id; 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 // 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 // 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 // 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 // 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( await userDAL.createUserEncryption(
{ {
userId: inviteeUserId, userId: inviteeUserId,
@@ -159,7 +159,7 @@ export const membershipUserServiceFactory = ({
const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); const hasNoPermanentRole = data.roles.every((el) => el.isTemporary);
if (hasNoPermanentRole) { if (hasNoPermanentRole) {
throw new BadRequestError({ 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) => { const isInvalidTemporaryRole = data.roles.some((el) => {
@@ -284,7 +284,7 @@ export const membershipUserServiceFactory = ({
const hasNoPermanentRole = data.roles.every((el) => el.isTemporary); const hasNoPermanentRole = data.roles.every((el) => el.isTemporary);
if (hasNoPermanentRole) { if (hasNoPermanentRole) {
throw new BadRequestError({ 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) => { const isInvalidTemporaryRole = data.roles.some((el) => {
@@ -15,6 +15,7 @@ export const orgMembershipDALFactory = (db: TDbClient) => {
.whereNotNull(`${TableName.Membership}.actorUserId`) .whereNotNull(`${TableName.Membership}.actorUserId`)
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`) .join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
.join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`) .join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
.leftJoin(TableName.Role, `${TableName.Role}.id`, `${TableName.MembershipRole}.customRoleId`)
.leftJoin<TUserEncryptionKeys>( .leftJoin<TUserEncryptionKeys>(
TableName.UserEncryptionKey, TableName.UserEncryptionKey,
`${TableName.UserEncryptionKey}.userId`, `${TableName.UserEncryptionKey}.userId`,
@@ -31,6 +32,7 @@ export const orgMembershipDALFactory = (db: TDbClient) => {
db.ref("scopeOrgId").withSchema(TableName.Membership).as("orgId"), db.ref("scopeOrgId").withSchema(TableName.Membership).as("orgId"),
db.ref("role").withSchema(TableName.MembershipRole), db.ref("role").withSchema(TableName.MembershipRole),
db.ref("customRoleId").withSchema(TableName.MembershipRole).as("roleId"), db.ref("customRoleId").withSchema(TableName.MembershipRole).as("roleId"),
db.ref("slug").withSchema(TableName.Role).as("customRoleSlug"),
db.ref("status").withSchema(TableName.Membership), db.ref("status").withSchema(TableName.Membership),
db.ref("isActive").withSchema(TableName.Membership), db.ref("isActive").withSchema(TableName.Membership),
db.ref("lastLoginAuthMethod").withSchema(TableName.Membership), db.ref("lastLoginAuthMethod").withSchema(TableName.Membership),
@@ -56,6 +58,7 @@ export const orgMembershipDALFactory = (db: TDbClient) => {
parentMapper: ({ parentMapper: ({
email, email,
isEmailVerified, isEmailVerified,
customRoleSlug,
username, username,
firstName, firstName,
lastName, lastName,
@@ -75,6 +78,7 @@ export const orgMembershipDALFactory = (db: TDbClient) => {
orgId, orgId,
id, id,
role, role,
customRoleSlug,
status, status,
isActive, isActive,
inviteEmail, inviteEmail,
+1 -1
View File
@@ -646,7 +646,7 @@ export const orgDALFactory = (db: TDbClient) => {
.replicaNode()(TableName.Membership) .replicaNode()(TableName.Membership)
.where({ actorIdentityId: identityId }) .where({ actorIdentityId: identityId })
.where(`${TableName.Membership}.scope`, AccessScope.Organization) .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.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
.join(TableName.Organization, `${TableName.Membership}.scopeOrgId`, `${TableName.Organization}.id`) .join(TableName.Organization, `${TableName.Membership}.scopeOrgId`, `${TableName.Organization}.id`)
.select(db.ref("id").withSchema(TableName.Organization).as("id")) .select(db.ref("id").withSchema(TableName.Organization).as("id"))
@@ -35,11 +35,11 @@ export const projectKeyDALFactory = (db: TDbClient) => {
const findAllProjectUserPubKeys = async (projectId: string, tx?: Knex) => { const findAllProjectUserPubKeys = async (projectId: string, tx?: Knex) => {
try { try {
const pubKeys = await (tx || db.replicaNode())(TableName.Membership) 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) .where(`${TableName.Membership}.scope`, AccessScope.Project)
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`) .join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
.join(TableName.UserEncryptionKey, `${TableName.Users}.id`, `${TableName.UserEncryptionKey}.userId`) .join(TableName.UserEncryptionKey, `${TableName.Users}.id`, `${TableName.UserEncryptionKey}.userId`)
.select("userId", "publicKey"); .select(db.ref("userId").withSchema(TableName.Users), "publicKey");
return pubKeys; return pubKeys;
} catch (error) { } catch (error) {
throw new DatabaseError({ error, name: "Find all workspace pub keys" }); throw new DatabaseError({ error, name: "Find all workspace pub keys" });
@@ -42,12 +42,7 @@ export const projectMembershipDALFactory = (db: TDbClient) => {
.select("role") .select("role")
.from(TableName.MembershipRole) .from(TableName.MembershipRole)
.leftJoin(TableName.Role, `${TableName.Role}.id`, `${TableName.MembershipRole}.customRoleId`) .leftJoin(TableName.Role, `${TableName.Role}.id`, `${TableName.MembershipRole}.customRoleId`)
.whereRaw("??.?? = ??.??", [ .whereRaw("??.?? = ??.??", [TableName.MembershipRole, "membershipId", TableName.Membership, "id"])
TableName.MembershipRole,
"projectMembershipId",
TableName.Membership,
"id"
])
.where((subQb) => { .where((subQb) => {
void subQb void subQb
.whereIn(`${TableName.MembershipRole}.role`, filter.roles as string[]) .whereIn(`${TableName.MembershipRole}.role`, filter.roles as string[])
@@ -31,7 +31,6 @@ export const projectDALFactory = (db: TDbClient) => {
.where(`${TableName.Membership}.actorIdentityId`, identityId) .where(`${TableName.Membership}.actorIdentityId`, identityId)
.join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`) .join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`)
.where(`${TableName.Project}.orgId`, orgId) .where(`${TableName.Project}.orgId`, orgId)
.join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`)
.andWhere((qb) => { .andWhere((qb) => {
if (projectType) { if (projectType) {
void qb.where(`${TableName.Project}.type`, projectType); void qb.where(`${TableName.Project}.type`, projectType);
+2 -2
View File
@@ -72,7 +72,7 @@ export const roleServiceFactory = ({
slug: data.slug, slug: data.slug,
[scope.key]: scope.value [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 || []), { validateHandlebarTemplate("Role Creation", JSON.stringify(data.permissions || []), {
allowedExpressions: (val) => val.includes("identity.") allowedExpressions: (val) => val.includes("identity.")
@@ -108,7 +108,7 @@ export const roleServiceFactory = ({
[scope.key]: scope.value [scope.key]: scope.value
}); });
if (existingSlug && existingRole.id !== existingSlug.id) 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 || []), { validateHandlebarTemplate("Role Update", JSON.stringify(data.permissions || []), {
@@ -597,7 +597,7 @@ export const superAdminServiceFactory = ({
{ {
actorIdentityId: newIdentity.id, actorIdentityId: newIdentity.id,
scopeOrgId: organization.id, scopeOrgId: organization.id,
scope: AccessScope.Project scope: AccessScope.Organization
}, },
tx tx
); );
@@ -947,6 +947,9 @@ export const superAdminServiceFactory = ({
} }
const membershipRole = await membershipRoleDAL.findOne({ membershipId }); const membershipRole = await membershipRoleDAL.findOne({ membershipId });
if (!membershipRole) {
throw new NotFoundError({ name: "Membership Role", message: "Membership role not found" });
}
const [organizationMembership] = await membershipUserDAL.delete({ const [organizationMembership] = await membershipUserDAL.delete({
scopeOrgId: organizationId, scopeOrgId: organizationId,
scope: AccessScope.Organization, scope: AccessScope.Organization,
+1
View File
@@ -64,6 +64,7 @@ export type OrgUser = {
inviteEmail: string; inviteEmail: string;
organization: string; organization: string;
role: "owner" | "admin" | "member" | "no-access" | "custom"; role: "owner" | "admin" | "member" | "no-access" | "custom";
customRoleSlug?: string;
status: "invited" | "accepted" | "verified" | "completed"; status: "invited" | "accepted" | "verified" | "completed";
deniedPermissions: any[]; deniedPermissions: any[];
roleId: string; roleId: string;
@@ -272,7 +272,7 @@ export const IdentityAuthTemplatesTable = ({ handlePopUpOpen }: Props) => {
/> />
)} )}
{!subscription.machineIdentityAuthTemplates && ( {!subscription.machineIdentityAuthTemplates && (
<EmptyState title="This feature is not been activated for your license." icon={faBan} /> <EmptyState title="This feature has not been activated for your license." icon={faBan} />
)} )}
{!isPending && templates.length === 0 && ( {!isPending && templates.length === 0 && (
<EmptyState <EmptyState
@@ -41,7 +41,7 @@ export const ExternalMigrationsTab = () => {
onClick={() => { onClick={() => {
handlePopUpOpen("selectImportPlatform"); handlePopUpOpen("selectImportPlatform");
}} }}
isDisabled={hasOrgRole(OrgMembershipRole.Admin)} isDisabled={!hasOrgRole(OrgMembershipRole.Admin)}
leftIcon={<FontAwesomeIcon icon={faPlus} />} leftIcon={<FontAwesomeIcon icon={faPlus} />}
> >
Import Import
@@ -76,7 +76,9 @@ export const UserDetailsSection = ({ membershipId, handlePopUpOpen }: Props) =>
return m.status === "invited" ? "Invited" : "Active"; 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 ? ( return membership ? (
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4"> <div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">