mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 15:28:25 +00:00
Access approval policy
This commit is contained in:
committed by
Daniel Hougaard
parent
c497e19b99
commit
c64334462f
@@ -1,9 +1,9 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName, TAccessApprovalPolicies } from "@app/db/schemas";
|
import { AccessApprovalPoliciesSchema, TableName, TAccessApprovalPolicies } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { buildFindFilter, mergeOneToManyRelation, ormify, selectAllTableCols, TFindFilter } from "@app/lib/knex";
|
import { buildFindFilter, ormify, selectAllTableCols, sqlNestRelationships, TFindFilter } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TAccessApprovalPolicyDALFactory = ReturnType<typeof accessApprovalPolicyDALFactory>;
|
export type TAccessApprovalPolicyDALFactory = ReturnType<typeof accessApprovalPolicyDALFactory>;
|
||||||
|
|
||||||
@@ -15,12 +15,12 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => {
|
|||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
.where(buildFindFilter(filter))
|
.where(buildFindFilter(filter))
|
||||||
.join(TableName.Environment, `${TableName.AccessApprovalPolicy}.envId`, `${TableName.Environment}.id`)
|
.join(TableName.Environment, `${TableName.AccessApprovalPolicy}.envId`, `${TableName.Environment}.id`)
|
||||||
.join(
|
.leftJoin(
|
||||||
TableName.AccessApprovalPolicyApprover,
|
TableName.AccessApprovalPolicyApprover,
|
||||||
`${TableName.AccessApprovalPolicy}.id`,
|
`${TableName.AccessApprovalPolicy}.id`,
|
||||||
`${TableName.AccessApprovalPolicyApprover}.policyId`
|
`${TableName.AccessApprovalPolicyApprover}.policyId`
|
||||||
)
|
)
|
||||||
.select(tx.ref("approverId").withSchema(TableName.AccessApprovalPolicyApprover))
|
.select(tx.ref("approverUserId").withSchema(TableName.AccessApprovalPolicyApprover))
|
||||||
.select(tx.ref("name").withSchema(TableName.Environment).as("envName"))
|
.select(tx.ref("name").withSchema(TableName.Environment).as("envName"))
|
||||||
.select(tx.ref("slug").withSchema(TableName.Environment).as("envSlug"))
|
.select(tx.ref("slug").withSchema(TableName.Environment).as("envSlug"))
|
||||||
.select(tx.ref("id").withSchema(TableName.Environment).as("envId"))
|
.select(tx.ref("id").withSchema(TableName.Environment).as("envId"))
|
||||||
@@ -35,18 +35,30 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => {
|
|||||||
const doc = await accessApprovalPolicyFindQuery(tx || db.replicaNode(), {
|
const doc = await accessApprovalPolicyFindQuery(tx || db.replicaNode(), {
|
||||||
[`${TableName.AccessApprovalPolicy}.id` as "id"]: id
|
[`${TableName.AccessApprovalPolicy}.id` as "id"]: id
|
||||||
});
|
});
|
||||||
const formatedDoc = mergeOneToManyRelation(
|
const formattedDoc = sqlNestRelationships({
|
||||||
doc,
|
data: doc,
|
||||||
"id",
|
key: "id",
|
||||||
({ approverId, envId, envName: name, envSlug: slug, ...el }) => ({
|
parentMapper: (data) => ({
|
||||||
...el,
|
environment: {
|
||||||
envId,
|
id: data.envId,
|
||||||
environment: { id: envId, name, slug }
|
name: data.envName,
|
||||||
|
slug: data.envSlug
|
||||||
|
},
|
||||||
|
projectId: data.projectId,
|
||||||
|
...AccessApprovalPoliciesSchema.parse(data)
|
||||||
}),
|
}),
|
||||||
({ approverId }) => approverId,
|
childrenMapper: [
|
||||||
"approvers"
|
{
|
||||||
);
|
key: "approverUserId",
|
||||||
return formatedDoc?.[0];
|
label: "userApprovers" as const,
|
||||||
|
mapper: ({ approverUserId }) => ({
|
||||||
|
userId: approverUserId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
return formattedDoc?.[0];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "FindById" });
|
throw new DatabaseError({ error, name: "FindById" });
|
||||||
}
|
}
|
||||||
@@ -55,18 +67,32 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => {
|
|||||||
const find = async (filter: TFindFilter<TAccessApprovalPolicies & { projectId: string }>, tx?: Knex) => {
|
const find = async (filter: TFindFilter<TAccessApprovalPolicies & { projectId: string }>, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const docs = await accessApprovalPolicyFindQuery(tx || db.replicaNode(), filter);
|
const docs = await accessApprovalPolicyFindQuery(tx || db.replicaNode(), filter);
|
||||||
const formatedDoc = mergeOneToManyRelation(
|
|
||||||
docs,
|
const formattedDocs = sqlNestRelationships({
|
||||||
"id",
|
data: docs,
|
||||||
({ approverId, envId, envName: name, envSlug: slug, ...el }) => ({
|
key: "id",
|
||||||
...el,
|
parentMapper: (data) => ({
|
||||||
envId,
|
environment: {
|
||||||
environment: { id: envId, name, slug }
|
id: data.envId,
|
||||||
|
name: data.envName,
|
||||||
|
slug: data.envSlug
|
||||||
|
},
|
||||||
|
projectId: data.projectId,
|
||||||
|
...AccessApprovalPoliciesSchema.parse(data)
|
||||||
|
// secretPath: data.secretPath || undefined,
|
||||||
}),
|
}),
|
||||||
({ approverId }) => approverId,
|
childrenMapper: [
|
||||||
"approvers"
|
{
|
||||||
);
|
key: "approverUserId",
|
||||||
return formatedDoc.map((policy) => ({ ...policy, secretPath: policy.secretPath || undefined }));
|
label: "userApprovers" as const,
|
||||||
|
mapper: ({ approverUserId }) => ({
|
||||||
|
userId: approverUserId
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
return formattedDocs;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Find" });
|
throw new DatabaseError({ error, name: "Find" });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
accessApprovalPolicyApproverDAL,
|
accessApprovalPolicyApproverDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
projectEnvDAL,
|
projectEnvDAL,
|
||||||
projectDAL,
|
projectDAL
|
||||||
projectMembershipDAL
|
|
||||||
}: TSecretApprovalPolicyServiceFactoryDep) => {
|
}: TSecretApprovalPolicyServiceFactoryDep) => {
|
||||||
const createAccessApprovalPolicy = async ({
|
const createAccessApprovalPolicy = async ({
|
||||||
name,
|
name,
|
||||||
@@ -45,7 +44,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
secretPath,
|
secretPath,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
approvals,
|
approvals,
|
||||||
approvers,
|
approverUserIds,
|
||||||
projectSlug,
|
projectSlug,
|
||||||
environment,
|
environment,
|
||||||
enforcementLevel
|
enforcementLevel
|
||||||
@@ -53,7 +52,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
if (!project) throw new BadRequestError({ message: "Project not found" });
|
if (!project) throw new BadRequestError({ message: "Project not found" });
|
||||||
|
|
||||||
if (approvals > approvers.length)
|
if (approvals > approverUserIds.length)
|
||||||
throw new BadRequestError({ message: "Approvals cannot be greater than approvers" });
|
throw new BadRequestError({ message: "Approvals cannot be greater than approvers" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getProjectPermission(
|
const { permission } = await permissionService.getProjectPermission(
|
||||||
@@ -70,15 +69,6 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
const env = await projectEnvDAL.findOne({ slug: environment, projectId: project.id });
|
const env = await projectEnvDAL.findOne({ slug: environment, projectId: project.id });
|
||||||
if (!env) throw new BadRequestError({ message: "Environment not found" });
|
if (!env) throw new BadRequestError({ message: "Environment not found" });
|
||||||
|
|
||||||
const secretApprovers = await projectMembershipDAL.find({
|
|
||||||
projectId: project.id,
|
|
||||||
$in: { id: approvers }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (secretApprovers.length !== approvers.length) {
|
|
||||||
throw new BadRequestError({ message: "Approver not found in project" });
|
|
||||||
}
|
|
||||||
|
|
||||||
await verifyApprovers({
|
await verifyApprovers({
|
||||||
projectId: project.id,
|
projectId: project.id,
|
||||||
orgId: actorOrgId,
|
orgId: actorOrgId,
|
||||||
@@ -86,7 +76,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
secretPath,
|
secretPath,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
permissionService,
|
permissionService,
|
||||||
userIds: secretApprovers.map((approver) => approver.userId)
|
userIds: approverUserIds
|
||||||
});
|
});
|
||||||
|
|
||||||
const accessApproval = await accessApprovalPolicyDAL.transaction(async (tx) => {
|
const accessApproval = await accessApprovalPolicyDAL.transaction(async (tx) => {
|
||||||
@@ -101,8 +91,8 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
await accessApprovalPolicyApproverDAL.insertMany(
|
await accessApprovalPolicyApproverDAL.insertMany(
|
||||||
secretApprovers.map(({ id }) => ({
|
approverUserIds.map((userId) => ({
|
||||||
approverId: id,
|
approverUserId: userId,
|
||||||
policyId: doc.id
|
policyId: doc.id
|
||||||
})),
|
})),
|
||||||
tx
|
tx
|
||||||
@@ -138,7 +128,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
|
|
||||||
const updateAccessApprovalPolicy = async ({
|
const updateAccessApprovalPolicy = async ({
|
||||||
policyId,
|
policyId,
|
||||||
approvers,
|
approverUserIds,
|
||||||
secretPath,
|
secretPath,
|
||||||
name,
|
name,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -171,16 +161,7 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
if (approvers) {
|
if (approverUserIds) {
|
||||||
// Find the workspace project memberships of the users passed in the approvers array
|
|
||||||
const secretApprovers = await projectMembershipDAL.find(
|
|
||||||
{
|
|
||||||
projectId: accessApprovalPolicy.projectId,
|
|
||||||
$in: { id: approvers }
|
|
||||||
},
|
|
||||||
{ tx }
|
|
||||||
);
|
|
||||||
|
|
||||||
await verifyApprovers({
|
await verifyApprovers({
|
||||||
projectId: accessApprovalPolicy.projectId,
|
projectId: accessApprovalPolicy.projectId,
|
||||||
orgId: actorOrgId,
|
orgId: actorOrgId,
|
||||||
@@ -188,15 +169,13 @@ export const accessApprovalPolicyServiceFactory = ({
|
|||||||
secretPath: doc.secretPath!,
|
secretPath: doc.secretPath!,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
permissionService,
|
permissionService,
|
||||||
userIds: secretApprovers.map((approver) => approver.userId)
|
userIds: approverUserIds
|
||||||
});
|
});
|
||||||
|
|
||||||
if (secretApprovers.length !== approvers.length)
|
|
||||||
throw new BadRequestError({ message: "Approvals cannot be greater than approvers" });
|
|
||||||
await accessApprovalPolicyApproverDAL.delete({ policyId: doc.id }, tx);
|
await accessApprovalPolicyApproverDAL.delete({ policyId: doc.id }, tx);
|
||||||
await accessApprovalPolicyApproverDAL.insertMany(
|
await accessApprovalPolicyApproverDAL.insertMany(
|
||||||
secretApprovers.map(({ id }) => ({
|
approverUserIds.map((userId) => ({
|
||||||
approverId: id,
|
approverUserId: userId,
|
||||||
policyId: doc.id
|
policyId: doc.id
|
||||||
})),
|
})),
|
||||||
tx
|
tx
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export type TCreateAccessApprovalPolicy = {
|
|||||||
approvals: number;
|
approvals: number;
|
||||||
secretPath: string;
|
secretPath: string;
|
||||||
environment: string;
|
environment: string;
|
||||||
approvers: string[];
|
approverUserIds: string[];
|
||||||
projectSlug: string;
|
projectSlug: string;
|
||||||
name: string;
|
name: string;
|
||||||
enforcementLevel: EnforcementLevel;
|
enforcementLevel: EnforcementLevel;
|
||||||
@@ -26,7 +26,7 @@ export type TCreateAccessApprovalPolicy = {
|
|||||||
export type TUpdateAccessApprovalPolicy = {
|
export type TUpdateAccessApprovalPolicy = {
|
||||||
policyId: string;
|
policyId: string;
|
||||||
approvals?: number;
|
approvals?: number;
|
||||||
approvers?: string[];
|
approverUserIds?: string[];
|
||||||
secretPath?: string;
|
secretPath?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
enforcementLevel?: EnforcementLevel;
|
enforcementLevel?: EnforcementLevel;
|
||||||
|
|||||||
Reference in New Issue
Block a user