mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-11 06:29:04 +00:00
feat: allow access approvals with user groups
This commit is contained in:
Vendored
+6
@@ -6,6 +6,7 @@ import {
|
||||
TAccessApprovalPoliciesApprovers,
|
||||
TAccessApprovalPoliciesApproversInsert,
|
||||
TAccessApprovalPoliciesApproversUpdate,
|
||||
TAccessApprovalPoliciesGroupApprovers,
|
||||
TAccessApprovalPoliciesInsert,
|
||||
TAccessApprovalPoliciesUpdate,
|
||||
TAccessApprovalRequests,
|
||||
@@ -800,5 +801,10 @@ declare module "knex/types/tables" {
|
||||
TWorkflowIntegrationsInsert,
|
||||
TWorkflowIntegrationsUpdate
|
||||
>;
|
||||
[TableName.AccessApprovalPolicyGroupApprover]: KnexOriginal.CompositeTableType<
|
||||
TAccessApprovalPoliciesGroupApprovers,
|
||||
TAccessApprovalPoliciesGroupApproversInsert,
|
||||
TAccessApprovalPoliciesGroupApproversInsert
|
||||
>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Knex } from "knex";
|
||||
|
||||
import { TableName } from "../schemas";
|
||||
import { createOnUpdateTrigger } from "../utils";
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
if (!(await knex.schema.hasTable(TableName.AccessApprovalPolicyGroupApprover))) {
|
||||
await knex.schema.createTable(TableName.AccessApprovalPolicyGroupApprover, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
t.uuid("approverGroupId").notNullable();
|
||||
t.foreign("approverGroupId").references("id").inTable(TableName.Groups).onDelete("CASCADE");
|
||||
t.uuid("policyId").notNullable();
|
||||
t.foreign("policyId").references("id").inTable(TableName.AccessApprovalPolicy).onDelete("CASCADE");
|
||||
t.timestamps(true, true, true);
|
||||
});
|
||||
await createOnUpdateTrigger(knex, TableName.AccessApprovalPolicyGroupApprover);
|
||||
}
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.dropTableIfExists(TableName.AccessApprovalPolicyGroupApprover);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Code generated by automation script, DO NOT EDIT.
|
||||
// Automated by pulling database and generating zod schema
|
||||
// To update. Just run npm run generate:schema
|
||||
// Written by akhilmhdh.
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
import { TImmutableDBKeys } from "./models";
|
||||
|
||||
export const AccessApprovalPoliciesGroupApproversSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
approverGroupId: z.string().uuid(),
|
||||
policyId: z.string().uuid(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date()
|
||||
});
|
||||
|
||||
export type TAccessApprovalPoliciesGroupApprovers = z.infer<typeof AccessApprovalPoliciesGroupApproversSchema>;
|
||||
export type TAccessApprovalPoliciesGroupApproversInsert = Omit<
|
||||
z.input<typeof AccessApprovalPoliciesGroupApproversSchema>,
|
||||
TImmutableDBKeys
|
||||
>;
|
||||
export type TAccessApprovalPoliciesGroupApproversUpdate = Partial<
|
||||
Omit<z.input<typeof AccessApprovalPoliciesGroupApproversSchema>, TImmutableDBKeys>
|
||||
>;
|
||||
@@ -1,5 +1,6 @@
|
||||
export * from "./access-approval-policies";
|
||||
export * from "./access-approval-policies-approvers";
|
||||
export * from "./access-approval-policies-group-approvers";
|
||||
export * from "./access-approval-requests";
|
||||
export * from "./access-approval-requests-reviewers";
|
||||
export * from "./api-keys";
|
||||
|
||||
@@ -73,6 +73,7 @@ export enum TableName {
|
||||
ScimToken = "scim_tokens",
|
||||
AccessApprovalPolicy = "access_approval_policies",
|
||||
AccessApprovalPolicyApprover = "access_approval_policies_approvers",
|
||||
AccessApprovalPolicyGroupApprover = "access_approval_policies_group_approvers",
|
||||
AccessApprovalRequest = "access_approval_requests",
|
||||
AccessApprovalRequestReviewer = "access_approval_requests_reviewers",
|
||||
SecretApprovalPolicy = "secret_approval_policies",
|
||||
|
||||
@@ -17,13 +17,14 @@ export const registerAccessApprovalPolicyRouter = async (server: FastifyZodProvi
|
||||
name: z.string().optional(),
|
||||
secretPath: z.string().trim().default("/"),
|
||||
environment: z.string(),
|
||||
approvers: z.string().array().min(1),
|
||||
approvers: z.string().array().default([]),
|
||||
groupApprovers: z.string().array().default([]),
|
||||
approvals: z.number().min(1).default(1),
|
||||
enforcementLevel: z.nativeEnum(EnforcementLevel).default(EnforcementLevel.Hard)
|
||||
})
|
||||
.refine((data) => data.approvals <= data.approvers.length, {
|
||||
path: ["approvals"],
|
||||
message: "The number of approvals should be lower than the number of approvers."
|
||||
.refine((data) => data.approvers.length > 0 || data.groupApprovers.length > 0, {
|
||||
path: ["approvers", "groupApprovers"],
|
||||
message: "At least one approver should be provided."
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -63,6 +64,11 @@ export const registerAccessApprovalPolicyRouter = async (server: FastifyZodProvi
|
||||
userId: z.string()
|
||||
})
|
||||
.array(),
|
||||
groupApprovers: z
|
||||
.object({
|
||||
groupId: z.string()
|
||||
})
|
||||
.array(),
|
||||
secretPath: z.string().optional().nullable()
|
||||
})
|
||||
.array()
|
||||
@@ -127,13 +133,14 @@ export const registerAccessApprovalPolicyRouter = async (server: FastifyZodProvi
|
||||
.trim()
|
||||
.optional()
|
||||
.transform((val) => (val === "" ? "/" : val)),
|
||||
approvers: z.string().array().min(1),
|
||||
approvals: z.number().min(1).default(1),
|
||||
approvers: z.string().array().optional().default([]),
|
||||
approvals: z.number().min(1).optional(),
|
||||
groupApprovers: z.string().array().optional().default([]),
|
||||
enforcementLevel: z.nativeEnum(EnforcementLevel).default(EnforcementLevel.Hard)
|
||||
})
|
||||
.refine((data) => data.approvals <= data.approvers.length, {
|
||||
path: ["approvals"],
|
||||
message: "The number of approvals should be lower than the number of approvers."
|
||||
.refine((data) => data.approvers || data.groupApprovers, {
|
||||
path: ["approvers", "groupApprovers"],
|
||||
message: "At least one approver should be provided."
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
|
||||
@@ -20,7 +20,13 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => {
|
||||
`${TableName.AccessApprovalPolicy}.id`,
|
||||
`${TableName.AccessApprovalPolicyApprover}.policyId`
|
||||
)
|
||||
.leftJoin(
|
||||
TableName.AccessApprovalPolicyGroupApprover,
|
||||
`${TableName.AccessApprovalPolicy}.id`,
|
||||
`${TableName.AccessApprovalPolicyGroupApprover}.policyId`
|
||||
)
|
||||
.select(tx.ref("approverUserId").withSchema(TableName.AccessApprovalPolicyApprover))
|
||||
.select(tx.ref("approverGroupId").withSchema(TableName.AccessApprovalPolicyGroupApprover))
|
||||
.select(tx.ref("name").withSchema(TableName.Environment).as("envName"))
|
||||
.select(tx.ref("slug").withSchema(TableName.Environment).as("envSlug"))
|
||||
.select(tx.ref("id").withSchema(TableName.Environment).as("envId"))
|
||||
@@ -54,6 +60,13 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => {
|
||||
mapper: ({ approverUserId }) => ({
|
||||
userId: approverUserId
|
||||
})
|
||||
},
|
||||
{
|
||||
key: "approverGroupId",
|
||||
label: "groupApprovers" as const,
|
||||
mapper: ({ approverGroupId }) => ({
|
||||
groupId: approverGroupId
|
||||
})
|
||||
}
|
||||
]
|
||||
});
|
||||
@@ -88,6 +101,13 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => {
|
||||
mapper: ({ approverUserId }) => ({
|
||||
userId: approverUserId
|
||||
})
|
||||
},
|
||||
{
|
||||
key: "approverGroupId",
|
||||
label: "groupApprovers" as const,
|
||||
mapper: ({ approverGroupId }) => ({
|
||||
groupId: approverGroupId
|
||||
})
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import { TDbClient } from "@app/db";
|
||||
import { TableName } from "@app/db/schemas";
|
||||
import { ormify } from "@app/lib/knex";
|
||||
|
||||
export type TAccessApprovalPolicyGroupApproverDALFactory = ReturnType<
|
||||
typeof accessApprovalPolicyGroupApproverDALFactory
|
||||
>;
|
||||
|
||||
export const accessApprovalPolicyGroupApproverDALFactory = (db: TDbClient) => {
|
||||
const accessApprovalPolicyGroupApproverOrm = ormify(db, TableName.AccessApprovalPolicyGroupApprover);
|
||||
return { ...accessApprovalPolicyGroupApproverOrm };
|
||||
};
|
||||
@@ -3,13 +3,16 @@ import { ForbiddenError } from "@casl/ability";
|
||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||
import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal";
|
||||
import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal";
|
||||
|
||||
import { TGroupDALFactory } from "../group/group-dal";
|
||||
import { TAccessApprovalPolicyApproverDALFactory } from "./access-approval-policy-approver-dal";
|
||||
import { TAccessApprovalPolicyDALFactory } from "./access-approval-policy-dal";
|
||||
import { verifyApprovers } from "./access-approval-policy-fns";
|
||||
import { TAccessApprovalPolicyGroupApproverDALFactory } from "./access-approval-policy-group-approver-dal";
|
||||
import {
|
||||
TCreateAccessApprovalPolicy,
|
||||
TDeleteAccessApprovalPolicy,
|
||||
@@ -25,13 +28,17 @@ type TSecretApprovalPolicyServiceFactoryDep = {
|
||||
projectEnvDAL: Pick<TProjectEnvDALFactory, "find" | "findOne">;
|
||||
accessApprovalPolicyApproverDAL: TAccessApprovalPolicyApproverDALFactory;
|
||||
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find">;
|
||||
groupDAL: TGroupDALFactory;
|
||||
accessApprovalPolicyGroupApproverDAL: TAccessApprovalPolicyGroupApproverDALFactory;
|
||||
};
|
||||
|
||||
export type TAccessApprovalPolicyServiceFactory = ReturnType<typeof accessApprovalPolicyServiceFactory>;
|
||||
|
||||
export const accessApprovalPolicyServiceFactory = ({
|
||||
accessApprovalPolicyDAL,
|
||||
accessApprovalPolicyGroupApproverDAL,
|
||||
accessApprovalPolicyApproverDAL,
|
||||
groupDAL,
|
||||
permissionService,
|
||||
projectEnvDAL,
|
||||
projectDAL
|
||||
@@ -45,6 +52,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
||||
actorAuthMethod,
|
||||
approvals,
|
||||
approvers,
|
||||
groupApprovers,
|
||||
projectSlug,
|
||||
environment,
|
||||
enforcementLevel
|
||||
@@ -52,7 +60,11 @@ export const accessApprovalPolicyServiceFactory = ({
|
||||
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||
if (!project) throw new BadRequestError({ message: "Project not found" });
|
||||
|
||||
if (approvals > approvers.length)
|
||||
if (!groupApprovers && !approvers)
|
||||
throw new BadRequestError({ message: "Either of approvers or group approvers must be provided" });
|
||||
|
||||
// If there is a group approver people might be added to the group later to meet the approvers quota
|
||||
if (!groupApprovers && approvals > approvers.length)
|
||||
throw new BadRequestError({ message: "Approvals cannot be greater than approvers" });
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
@@ -69,6 +81,35 @@ export const accessApprovalPolicyServiceFactory = ({
|
||||
const env = await projectEnvDAL.findOne({ slug: environment, projectId: project.id });
|
||||
if (!env) throw new BadRequestError({ message: "Environment not found" });
|
||||
|
||||
const verifyAllApprovers = approvers;
|
||||
const usersPromises: Promise<
|
||||
{
|
||||
id: string;
|
||||
email: string | null | undefined;
|
||||
username: string;
|
||||
firstName: string | null | undefined;
|
||||
lastName: string | null | undefined;
|
||||
isPartOfGroup: boolean;
|
||||
}[]
|
||||
>[] = [];
|
||||
|
||||
for (const groupId of groupApprovers) {
|
||||
usersPromises.push(groupDAL.findAllGroupMembers({ orgId: actorOrgId, groupId, offset: 0 }));
|
||||
}
|
||||
const verifyGroupApprovers = (await Promise.all(usersPromises)).flat().map((user) => user.id);
|
||||
verifyAllApprovers.push(...verifyGroupApprovers);
|
||||
|
||||
logger.info("verifyApproversCreate");
|
||||
logger.info({
|
||||
projectId: project.id,
|
||||
orgId: actorOrgId,
|
||||
envSlug: environment,
|
||||
secretPath,
|
||||
actorAuthMethod,
|
||||
permissionService,
|
||||
userIds: verifyAllApprovers
|
||||
});
|
||||
|
||||
await verifyApprovers({
|
||||
projectId: project.id,
|
||||
orgId: actorOrgId,
|
||||
@@ -76,7 +117,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
||||
secretPath,
|
||||
actorAuthMethod,
|
||||
permissionService,
|
||||
userIds: approvers
|
||||
userIds: verifyAllApprovers
|
||||
});
|
||||
|
||||
const accessApproval = await accessApprovalPolicyDAL.transaction(async (tx) => {
|
||||
@@ -97,6 +138,15 @@ export const accessApprovalPolicyServiceFactory = ({
|
||||
})),
|
||||
tx
|
||||
);
|
||||
|
||||
await accessApprovalPolicyGroupApproverDAL.insertMany(
|
||||
groupApprovers.map((groupId) => ({
|
||||
approverGroupId: groupId,
|
||||
policyId: doc.id
|
||||
})),
|
||||
tx
|
||||
);
|
||||
|
||||
return doc;
|
||||
});
|
||||
return { ...accessApproval, environment: env, projectId: project.id };
|
||||
@@ -129,6 +179,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
||||
const updateAccessApprovalPolicy = async ({
|
||||
policyId,
|
||||
approvers,
|
||||
groupApprovers,
|
||||
secretPath,
|
||||
name,
|
||||
actorId,
|
||||
@@ -162,6 +213,16 @@ export const accessApprovalPolicyServiceFactory = ({
|
||||
tx
|
||||
);
|
||||
if (approvers) {
|
||||
logger.info("verifyApproversPatch");
|
||||
logger.info({
|
||||
projectId: accessApprovalPolicy.projectId,
|
||||
orgId: actorOrgId,
|
||||
envSlug: accessApprovalPolicy.environment.slug,
|
||||
secretPath,
|
||||
actorAuthMethod,
|
||||
permissionService,
|
||||
userIds: approvers
|
||||
});
|
||||
await verifyApprovers({
|
||||
projectId: accessApprovalPolicy.projectId,
|
||||
orgId: actorOrgId,
|
||||
@@ -171,7 +232,6 @@ export const accessApprovalPolicyServiceFactory = ({
|
||||
permissionService,
|
||||
userIds: approvers
|
||||
});
|
||||
|
||||
await accessApprovalPolicyApproverDAL.delete({ policyId: doc.id }, tx);
|
||||
await accessApprovalPolicyApproverDAL.insertMany(
|
||||
approvers.map((userId) => ({
|
||||
@@ -181,6 +241,43 @@ export const accessApprovalPolicyServiceFactory = ({
|
||||
tx
|
||||
);
|
||||
}
|
||||
|
||||
if (groupApprovers) {
|
||||
const usersPromises: Promise<
|
||||
{
|
||||
id: string;
|
||||
email: string | null | undefined;
|
||||
username: string;
|
||||
firstName: string | null | undefined;
|
||||
lastName: string | null | undefined;
|
||||
isPartOfGroup: boolean;
|
||||
}[]
|
||||
>[] = [];
|
||||
|
||||
for (const groupId of groupApprovers) {
|
||||
usersPromises.push(groupDAL.findAllGroupMembers({ orgId: actorOrgId, groupId, offset: 0 }));
|
||||
}
|
||||
const verifyGroupApprovers = (await Promise.all(usersPromises)).flat().map((user) => user.id);
|
||||
|
||||
await verifyApprovers({
|
||||
projectId: accessApprovalPolicy.projectId,
|
||||
orgId: actorOrgId,
|
||||
envSlug: accessApprovalPolicy.environment.slug,
|
||||
secretPath: doc.secretPath!,
|
||||
actorAuthMethod,
|
||||
permissionService,
|
||||
userIds: verifyGroupApprovers
|
||||
});
|
||||
await accessApprovalPolicyGroupApproverDAL.delete({ policyId: doc.id }, tx);
|
||||
await accessApprovalPolicyGroupApproverDAL.insertMany(
|
||||
groupApprovers.map((groupId) => ({
|
||||
approverGroupId: groupId,
|
||||
policyId: doc.id
|
||||
})),
|
||||
tx
|
||||
);
|
||||
}
|
||||
|
||||
return doc;
|
||||
});
|
||||
return {
|
||||
|
||||
@@ -18,6 +18,7 @@ export type TCreateAccessApprovalPolicy = {
|
||||
secretPath: string;
|
||||
environment: string;
|
||||
approvers: string[];
|
||||
groupApprovers: string[];
|
||||
projectSlug: string;
|
||||
name: string;
|
||||
enforcementLevel: EnforcementLevel;
|
||||
@@ -27,6 +28,7 @@ export type TUpdateAccessApprovalPolicy = {
|
||||
policyId: string;
|
||||
approvals?: number;
|
||||
approvers?: string[];
|
||||
groupApprovers?: string[];
|
||||
secretPath?: string;
|
||||
name?: string;
|
||||
enforcementLevel?: EnforcementLevel;
|
||||
|
||||
@@ -39,6 +39,17 @@ export const accessApprovalRequestDALFactory = (db: TDbClient) => {
|
||||
`${TableName.AccessApprovalPolicy}.id`,
|
||||
`${TableName.AccessApprovalPolicyApprover}.policyId`
|
||||
)
|
||||
.leftJoin(
|
||||
TableName.AccessApprovalPolicyGroupApprover,
|
||||
`${TableName.AccessApprovalPolicy}.id`,
|
||||
`${TableName.AccessApprovalPolicyGroupApprover}.policyId`
|
||||
)
|
||||
.leftJoin(
|
||||
TableName.UserGroupMembership,
|
||||
`${TableName.AccessApprovalPolicyGroupApprover}.approverGroupId`,
|
||||
`${TableName.UserGroupMembership}.groupId`
|
||||
)
|
||||
.leftJoin(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
||||
|
||||
.join<TUsers>(
|
||||
db(TableName.Users).as("requestedByUser"),
|
||||
@@ -59,6 +70,7 @@ export const accessApprovalRequestDALFactory = (db: TDbClient) => {
|
||||
)
|
||||
|
||||
.select(db.ref("approverUserId").withSchema(TableName.AccessApprovalPolicyApprover))
|
||||
.select(db.ref("userId").withSchema(TableName.UserGroupMembership).as("approverGroupUserId"))
|
||||
|
||||
.select(
|
||||
db.ref("projectId").withSchema(TableName.Environment),
|
||||
@@ -142,7 +154,12 @@ export const accessApprovalRequestDALFactory = (db: TDbClient) => {
|
||||
label: "reviewers" as const,
|
||||
mapper: ({ reviewerUserId: userId, reviewerStatus: status }) => (userId ? { userId, status } : undefined)
|
||||
},
|
||||
{ key: "approverUserId", label: "approvers" as const, mapper: ({ approverUserId }) => approverUserId }
|
||||
{ key: "approverUserId", label: "approvers" as const, mapper: ({ approverUserId }) => approverUserId },
|
||||
{
|
||||
key: "approverGroupUserId",
|
||||
label: "approvers" as const,
|
||||
mapper: ({ approverGroupUserId }) => approverGroupUserId
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
@@ -172,18 +189,36 @@ export const accessApprovalRequestDALFactory = (db: TDbClient) => {
|
||||
`requestedByUser.id`
|
||||
)
|
||||
|
||||
.join(
|
||||
.leftJoin(
|
||||
TableName.AccessApprovalPolicyApprover,
|
||||
`${TableName.AccessApprovalPolicy}.id`,
|
||||
`${TableName.AccessApprovalPolicyApprover}.policyId`
|
||||
)
|
||||
|
||||
.join<TUsers>(
|
||||
.leftJoin<TUsers>(
|
||||
db(TableName.Users).as("accessApprovalPolicyApproverUser"),
|
||||
`${TableName.AccessApprovalPolicyApprover}.approverUserId`,
|
||||
"accessApprovalPolicyApproverUser.id"
|
||||
)
|
||||
|
||||
.leftJoin(
|
||||
TableName.AccessApprovalPolicyGroupApprover,
|
||||
`${TableName.AccessApprovalPolicy}.id`,
|
||||
`${TableName.AccessApprovalPolicyGroupApprover}.policyId`
|
||||
)
|
||||
|
||||
.leftJoin(
|
||||
TableName.UserGroupMembership,
|
||||
`${TableName.AccessApprovalPolicyGroupApprover}.approverGroupId`,
|
||||
`${TableName.UserGroupMembership}.groupId`
|
||||
)
|
||||
|
||||
.leftJoin<TUsers>(
|
||||
db(TableName.Users).as("accessApprovalPolicyGroupApproverUser"),
|
||||
`${TableName.UserGroupMembership}.userId`,
|
||||
"accessApprovalPolicyGroupApproverUser.id"
|
||||
)
|
||||
|
||||
.leftJoin(
|
||||
TableName.AccessApprovalRequestReviewer,
|
||||
`${TableName.AccessApprovalRequest}.id`,
|
||||
@@ -200,10 +235,15 @@ export const accessApprovalRequestDALFactory = (db: TDbClient) => {
|
||||
.select(selectAllTableCols(TableName.AccessApprovalRequest))
|
||||
.select(
|
||||
tx.ref("approverUserId").withSchema(TableName.AccessApprovalPolicyApprover),
|
||||
tx.ref("userId").withSchema(TableName.UserGroupMembership),
|
||||
tx.ref("email").withSchema("accessApprovalPolicyApproverUser").as("approverEmail"),
|
||||
tx.ref("email").withSchema("accessApprovalPolicyGroupApproverUser").as("approverGroupEmail"),
|
||||
tx.ref("username").withSchema("accessApprovalPolicyApproverUser").as("approverUsername"),
|
||||
tx.ref("username").withSchema("accessApprovalPolicyGroupApproverUser").as("approverGroupUsername"),
|
||||
tx.ref("firstName").withSchema("accessApprovalPolicyApproverUser").as("approverFirstName"),
|
||||
tx.ref("firstName").withSchema("accessApprovalPolicyGroupApproverUser").as("approverGroupFirstName"),
|
||||
tx.ref("lastName").withSchema("accessApprovalPolicyApproverUser").as("approverLastName"),
|
||||
tx.ref("lastName").withSchema("accessApprovalPolicyGroupApproverUser").as("approverGroupLastName"),
|
||||
tx.ref("email").withSchema("requestedByUser").as("requestedByUserEmail"),
|
||||
tx.ref("username").withSchema("requestedByUser").as("requestedByUserUsername"),
|
||||
tx.ref("firstName").withSchema("requestedByUser").as("requestedByUserFirstName"),
|
||||
@@ -282,6 +322,23 @@ export const accessApprovalRequestDALFactory = (db: TDbClient) => {
|
||||
lastName,
|
||||
username
|
||||
})
|
||||
},
|
||||
{
|
||||
key: "userId",
|
||||
label: "approvers" as const,
|
||||
mapper: ({
|
||||
userId,
|
||||
approverGroupEmail: email,
|
||||
approverGroupUsername: username,
|
||||
approverGroupLastName: lastName,
|
||||
approverFirstName: firstName
|
||||
}) => ({
|
||||
userId,
|
||||
email,
|
||||
firstName,
|
||||
lastName,
|
||||
username
|
||||
})
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
@@ -18,6 +18,8 @@ import { TUserDALFactory } from "@app/services/user/user-dal";
|
||||
import { TAccessApprovalPolicyApproverDALFactory } from "../access-approval-policy/access-approval-policy-approver-dal";
|
||||
import { TAccessApprovalPolicyDALFactory } from "../access-approval-policy/access-approval-policy-dal";
|
||||
import { verifyApprovers } from "../access-approval-policy/access-approval-policy-fns";
|
||||
import { TAccessApprovalPolicyGroupApproverDALFactory } from "../access-approval-policy/access-approval-policy-group-approver-dal";
|
||||
import { TGroupDALFactory } from "../group/group-dal";
|
||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
||||
import { TProjectUserAdditionalPrivilegeDALFactory } from "../project-user-additional-privilege/project-user-additional-privilege-dal";
|
||||
import { ProjectUserAdditionalPrivilegeTemporaryMode } from "../project-user-additional-privilege/project-user-additional-privilege-types";
|
||||
@@ -36,6 +38,7 @@ type TSecretApprovalRequestServiceFactoryDep = {
|
||||
additionalPrivilegeDAL: Pick<TProjectUserAdditionalPrivilegeDALFactory, "create" | "findById">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||
accessApprovalPolicyApproverDAL: Pick<TAccessApprovalPolicyApproverDALFactory, "find">;
|
||||
accessApprovalPolicyGroupApproverDAL: Pick<TAccessApprovalPolicyGroupApproverDALFactory, "find">;
|
||||
projectEnvDAL: Pick<TProjectEnvDALFactory, "findOne">;
|
||||
projectDAL: Pick<
|
||||
TProjectDALFactory,
|
||||
@@ -57,6 +60,7 @@ type TSecretApprovalRequestServiceFactoryDep = {
|
||||
TAccessApprovalRequestReviewerDALFactory,
|
||||
"create" | "find" | "findOne" | "transaction"
|
||||
>;
|
||||
groupDAL: Pick<TGroupDALFactory, "findAllGroupMembers">;
|
||||
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "findById">;
|
||||
smtpService: Pick<TSmtpService, "sendMail">;
|
||||
userDAL: Pick<
|
||||
@@ -70,6 +74,7 @@ type TSecretApprovalRequestServiceFactoryDep = {
|
||||
export type TAccessApprovalRequestServiceFactory = ReturnType<typeof accessApprovalRequestServiceFactory>;
|
||||
|
||||
export const accessApprovalRequestServiceFactory = ({
|
||||
groupDAL,
|
||||
projectDAL,
|
||||
projectEnvDAL,
|
||||
permissionService,
|
||||
@@ -78,6 +83,7 @@ export const accessApprovalRequestServiceFactory = ({
|
||||
projectMembershipDAL,
|
||||
accessApprovalPolicyDAL,
|
||||
accessApprovalPolicyApproverDAL,
|
||||
accessApprovalPolicyGroupApproverDAL,
|
||||
additionalPrivilegeDAL,
|
||||
smtpService,
|
||||
userDAL,
|
||||
@@ -124,13 +130,35 @@ export const accessApprovalRequestServiceFactory = ({
|
||||
});
|
||||
if (!policy) throw new UnauthorizedError({ message: "No policy matching criteria was found." });
|
||||
|
||||
const approverIds = [];
|
||||
|
||||
const approvers = await accessApprovalPolicyApproverDAL.find({
|
||||
policyId: policy.id
|
||||
});
|
||||
|
||||
approvers.forEach((approver) => {
|
||||
approverIds.push(approver.approverUserId);
|
||||
});
|
||||
|
||||
const groupApprovers = await accessApprovalPolicyGroupApproverDAL.find({
|
||||
policyId: policy.id
|
||||
});
|
||||
|
||||
const groupUsers = (
|
||||
await Promise.all(
|
||||
groupApprovers.map((groupApprover) =>
|
||||
groupDAL.findAllGroupMembers({
|
||||
orgId: actorOrgId,
|
||||
groupId: groupApprover.id
|
||||
})
|
||||
)
|
||||
)
|
||||
).flat();
|
||||
approverIds.push(...groupUsers.map((user) => user.id));
|
||||
|
||||
const approverUsers = await userDAL.find({
|
||||
$in: {
|
||||
id: approvers.map((approver) => approver.approverUserId)
|
||||
id: [...new Set(approverIds)]
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import { registerCertificateEstRouter } from "@app/ee/routes/est/certificate-est
|
||||
import { registerV1EERoutes } from "@app/ee/routes/v1";
|
||||
import { accessApprovalPolicyApproverDALFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-approver-dal";
|
||||
import { accessApprovalPolicyDALFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-dal";
|
||||
import { accessApprovalPolicyGroupApproverDALFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-group-approver-dal";
|
||||
import { accessApprovalPolicyServiceFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-service";
|
||||
import { accessApprovalRequestDALFactory } from "@app/ee/services/access-approval-request/access-approval-request-dal";
|
||||
import { accessApprovalRequestReviewerDALFactory } from "@app/ee/services/access-approval-request/access-approval-request-reviewer-dal";
|
||||
@@ -626,6 +627,7 @@ export const registerRoutes = async (
|
||||
const pkiAlertDAL = pkiAlertDALFactory(db);
|
||||
const pkiCollectionDAL = pkiCollectionDALFactory(db);
|
||||
const pkiCollectionItemDAL = pkiCollectionItemDALFactory(db);
|
||||
const accessApprovalPolicyGroupApproverDAL = accessApprovalPolicyGroupApproverDALFactory(db);
|
||||
|
||||
const certificateService = certificateServiceFactory({
|
||||
certificateDAL,
|
||||
@@ -923,6 +925,8 @@ export const registerRoutes = async (
|
||||
const accessApprovalPolicyService = accessApprovalPolicyServiceFactory({
|
||||
accessApprovalPolicyDAL,
|
||||
accessApprovalPolicyApproverDAL,
|
||||
accessApprovalPolicyGroupApproverDAL,
|
||||
groupDAL,
|
||||
permissionService,
|
||||
projectEnvDAL,
|
||||
projectMembershipDAL,
|
||||
@@ -942,7 +946,9 @@ export const registerRoutes = async (
|
||||
smtpService,
|
||||
accessApprovalPolicyApproverDAL,
|
||||
projectSlackConfigDAL,
|
||||
kmsService
|
||||
kmsService,
|
||||
accessApprovalPolicyGroupApproverDAL,
|
||||
groupDAL
|
||||
});
|
||||
|
||||
const secretReplicationService = secretReplicationServiceFactory({
|
||||
|
||||
Reference in New Issue
Block a user