mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
list policies endpoint
This commit is contained in:
@@ -58,6 +58,33 @@ export const registerApprovalPolicyEndpoints = <P extends TApprovalPolicy>({
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "GET",
|
||||
url: "/",
|
||||
config: {
|
||||
rateLimit: readLimit
|
||||
},
|
||||
schema: {
|
||||
description: "List approval policies",
|
||||
querystring: z.object({
|
||||
projectId: z.string().uuid()
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
policies: z.array(policyResponseSchema)
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
handler: async (req) => {
|
||||
const { policies } = await server.services.approvalPolicy.list(policyType, req.query.projectId, req.permission);
|
||||
|
||||
// TODO: Audit log
|
||||
|
||||
return { policies };
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "GET",
|
||||
url: "/:policyId",
|
||||
|
||||
@@ -3,7 +3,8 @@ import { TableName } from "@app/db/schemas";
|
||||
import { DatabaseError } from "@app/lib/errors";
|
||||
import { ormify } from "@app/lib/knex";
|
||||
|
||||
import { ApproverType } from "./approval-policy-enums";
|
||||
import { ApprovalPolicyType, ApproverType } from "./approval-policy-enums";
|
||||
import { ApprovalPolicyStep } from "./approval-policy-types";
|
||||
|
||||
// Approval Policy
|
||||
export type TApprovalPolicyDALFactory = ReturnType<typeof approvalPolicyDALFactory>;
|
||||
@@ -25,25 +26,23 @@ export const approvalPolicyDALFactory = (db: TDbClient) => {
|
||||
.whereIn("policyStepId", stepIds)
|
||||
.select("policyStepId", "userId", "groupId");
|
||||
|
||||
const approversByStepId = approvers.reduce<Record<string, { type: string; id: string }[]>>((acc, approver) => {
|
||||
const stepApprovers = acc[approver.policyStepId] || [];
|
||||
stepApprovers.push({
|
||||
type: approver.userId ? ApproverType.User : ApproverType.Group,
|
||||
id: (approver.userId || approver.groupId) as string
|
||||
});
|
||||
acc[approver.policyStepId] = stepApprovers;
|
||||
return acc;
|
||||
}, {});
|
||||
const approversByStepId = approvers.reduce<Record<string, { type: ApproverType; id: string }[]>>(
|
||||
(acc, approver) => {
|
||||
const stepApprovers = acc[approver.policyStepId] || [];
|
||||
stepApprovers.push({
|
||||
type: approver.userId ? ApproverType.User : ApproverType.Group,
|
||||
id: (approver.userId || approver.groupId) as string
|
||||
});
|
||||
acc[approver.policyStepId] = stepApprovers;
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
return steps.map((step) => {
|
||||
const stepApprovers = approversByStepId[step.id] || [];
|
||||
|
||||
const formattedStep: {
|
||||
name?: string;
|
||||
requiredApprovals: number;
|
||||
notifyApprovers?: boolean;
|
||||
approvers: { type: string; id: string }[];
|
||||
} = {
|
||||
const formattedStep: ApprovalPolicyStep = {
|
||||
requiredApprovals: step.requiredApprovals,
|
||||
approvers: stepApprovers
|
||||
};
|
||||
@@ -62,9 +61,77 @@ export const approvalPolicyDALFactory = (db: TDbClient) => {
|
||||
}
|
||||
};
|
||||
|
||||
const findByProjectId = async (policyType: ApprovalPolicyType, projectId: string) => {
|
||||
try {
|
||||
const dbInstance = db.replicaNode();
|
||||
const policies = await dbInstance(TableName.ApprovalPolicies).where({ type: policyType, projectId });
|
||||
|
||||
if (!policies.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const policyIds = policies.map((p) => p.id);
|
||||
|
||||
const steps = await dbInstance(TableName.ApprovalPolicySteps)
|
||||
.whereIn("policyId", policyIds)
|
||||
.orderBy("stepNumber", "asc");
|
||||
|
||||
const stepsByPolicyId: Record<string, ApprovalPolicyStep[]> = {};
|
||||
|
||||
if (steps.length) {
|
||||
const stepIds = steps.map((step) => step.id);
|
||||
|
||||
const approvers = await dbInstance(TableName.ApprovalPolicyStepApprovers)
|
||||
.whereIn("policyStepId", stepIds)
|
||||
.select("policyStepId", "userId", "groupId");
|
||||
|
||||
const approversByStepId = approvers.reduce<Record<string, { type: ApproverType; id: string }[]>>(
|
||||
(acc, approver) => {
|
||||
const stepApprovers = acc[approver.policyStepId] || [];
|
||||
stepApprovers.push({
|
||||
type: approver.userId ? ApproverType.User : ApproverType.Group,
|
||||
id: (approver.userId || approver.groupId) as string
|
||||
});
|
||||
acc[approver.policyStepId] = stepApprovers;
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
steps.forEach((step) => {
|
||||
const stepApprovers = approversByStepId[step.id] || [];
|
||||
const formattedStep: ApprovalPolicyStep = {
|
||||
requiredApprovals: step.requiredApprovals,
|
||||
approvers: stepApprovers
|
||||
};
|
||||
|
||||
if (step.name) {
|
||||
formattedStep.name = step.name;
|
||||
}
|
||||
if (typeof step.notifyApprovers === "boolean") {
|
||||
formattedStep.notifyApprovers = step.notifyApprovers;
|
||||
}
|
||||
|
||||
if (!stepsByPolicyId[step.policyId]) {
|
||||
stepsByPolicyId[step.policyId] = [];
|
||||
}
|
||||
stepsByPolicyId[step.policyId].push(formattedStep);
|
||||
});
|
||||
}
|
||||
|
||||
return policies.map((policy) => ({
|
||||
...policy,
|
||||
steps: stepsByPolicyId[policy.id] || []
|
||||
}));
|
||||
} catch (error) {
|
||||
throw new DatabaseError({ error, name: "Find approval policies by project id" });
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
...orm,
|
||||
findStepsByPolicyId
|
||||
findStepsByPolicyId,
|
||||
findByProjectId
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -122,6 +122,25 @@ export const approvalPolicyServiceFactory = ({
|
||||
};
|
||||
};
|
||||
|
||||
const list = async (policyType: ApprovalPolicyType, projectId: string, actor: OrgServiceActor) => {
|
||||
const { hasRole } = await permissionService.getProjectPermission({
|
||||
actor: actor.type,
|
||||
actorAuthMethod: actor.authMethod,
|
||||
actorId: actor.id,
|
||||
actorOrgId: actor.orgId,
|
||||
projectId,
|
||||
actionProjectType: ActionProjectType.Any
|
||||
});
|
||||
|
||||
if (!hasRole(ProjectMembershipRole.Admin)) {
|
||||
throw new ForbiddenRequestError({ message: "User has insufficient privileges" });
|
||||
}
|
||||
|
||||
const policies = await approvalPolicyDAL.findByProjectId(policyType, projectId);
|
||||
|
||||
return { policies };
|
||||
};
|
||||
|
||||
const getById = async (policyId: string, actor: OrgServiceActor) => {
|
||||
const policy = await approvalPolicyDAL.findById(policyId);
|
||||
if (!policy) {
|
||||
@@ -270,6 +289,7 @@ export const approvalPolicyServiceFactory = ({
|
||||
|
||||
return {
|
||||
create,
|
||||
list,
|
||||
getById,
|
||||
updateById,
|
||||
deleteById
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { TApprovalPolicyDALFactory, TApprovalRequestGrantsDALFactory } from "./approval-policy-dal";
|
||||
import {
|
||||
TApprovalPolicyDALFactory,
|
||||
TApprovalRequestGrantsDALFactory
|
||||
} from "@app/services/approval-policy/approval-policy-dal";
|
||||
|
||||
import { ApprovalPolicyType, ApproverType } from "./approval-policy-enums";
|
||||
import {
|
||||
TPamAccessPolicy,
|
||||
@@ -12,6 +16,16 @@ export type TApprovalPolicyInputs = TPamAccessPolicyInputs;
|
||||
export type TApprovalPolicyConditions = TPamAccessPolicyConditions;
|
||||
export type TApprovalPolicyConstraints = TPamAccessPolicyConstraints;
|
||||
|
||||
export interface ApprovalPolicyStep {
|
||||
name?: string | null;
|
||||
requiredApprovals: number;
|
||||
notifyApprovers?: boolean;
|
||||
approvers: {
|
||||
type: ApproverType;
|
||||
id: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
// DTOs
|
||||
export interface TCreatePolicyDTO {
|
||||
projectId: TApprovalPolicy["projectId"];
|
||||
@@ -19,15 +33,7 @@ export interface TCreatePolicyDTO {
|
||||
maxRequestTtlSeconds?: TApprovalPolicy["maxRequestTtlSeconds"];
|
||||
conditions: TApprovalPolicy["conditions"]["conditions"];
|
||||
constraints: TApprovalPolicy["constraints"]["constraints"];
|
||||
steps: {
|
||||
name?: string | null;
|
||||
requiredApprovals: number;
|
||||
notifyApprovers?: boolean;
|
||||
approvers: {
|
||||
type: ApproverType.User | ApproverType.Group;
|
||||
id: string;
|
||||
}[];
|
||||
}[];
|
||||
steps: ApprovalPolicyStep[];
|
||||
}
|
||||
|
||||
export interface TUpdatePolicyDTO {
|
||||
@@ -35,15 +41,7 @@ export interface TUpdatePolicyDTO {
|
||||
maxRequestTtlSeconds?: TApprovalPolicy["maxRequestTtlSeconds"];
|
||||
conditions?: TApprovalPolicy["conditions"]["conditions"];
|
||||
constraints?: TApprovalPolicy["constraints"]["constraints"];
|
||||
steps?: {
|
||||
name?: string | null;
|
||||
requiredApprovals: number;
|
||||
notifyApprovers?: boolean;
|
||||
approvers: {
|
||||
type: ApproverType.User | ApproverType.Group;
|
||||
id: string;
|
||||
}[];
|
||||
}[];
|
||||
steps?: ApprovalPolicyStep[];
|
||||
}
|
||||
|
||||
// Factory
|
||||
|
||||
Reference in New Issue
Block a user