diff --git a/backend/src/ee/services/access-approval-policy/access-approval-policy-approver-dal.ts b/backend/src/ee/services/access-approval-policy/access-approval-policy-approver-dal.ts index c141c762b..ee7157e72 100644 --- a/backend/src/ee/services/access-approval-policy/access-approval-policy-approver-dal.ts +++ b/backend/src/ee/services/access-approval-policy/access-approval-policy-approver-dal.ts @@ -1,15 +1,15 @@ import { TDbClient } from "@app/db"; import { TableName } from "@app/db/schemas"; -import { ormify } from "@app/lib/knex"; +import { ormify, TOrmify } from "@app/lib/knex"; -export type TAccessApprovalPolicyApproverDALFactory = ReturnType; +export type TAccessApprovalPolicyApproverDALFactory = TOrmify; export const accessApprovalPolicyApproverDALFactory = (db: TDbClient) => { const accessApprovalPolicyApproverOrm = ormify(db, TableName.AccessApprovalPolicyApprover); return { ...accessApprovalPolicyApproverOrm }; }; -export type TAccessApprovalPolicyBypasserDALFactory = ReturnType; +export type TAccessApprovalPolicyBypasserDALFactory = TOrmify; export const accessApprovalPolicyBypasserDALFactory = (db: TDbClient) => { const accessApprovalPolicyBypasserOrm = ormify(db, TableName.AccessApprovalPolicyBypasser); diff --git a/backend/src/ee/services/access-approval-policy/access-approval-policy-dal.ts b/backend/src/ee/services/access-approval-policy/access-approval-policy-dal.ts index dbcc5ed14..9fa48ca15 100644 --- a/backend/src/ee/services/access-approval-policy/access-approval-policy-dal.ts +++ b/backend/src/ee/services/access-approval-policy/access-approval-policy-dal.ts @@ -3,13 +3,363 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; import { AccessApprovalPoliciesSchema, TableName, TAccessApprovalPolicies, TUsers } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; -import { buildFindFilter, ormify, selectAllTableCols, sqlNestRelationships, TFindFilter } from "@app/lib/knex"; +import { buildFindFilter, ormify, selectAllTableCols, sqlNestRelationships, TFindFilter, TOrmify } from "@app/lib/knex"; -import { ApproverType, BypasserType } from "./access-approval-policy-types"; +import { + ApproverType, + BypasserType, + TCreateAccessApprovalPolicy, + TDeleteAccessApprovalPolicy, + TGetAccessApprovalPolicyByIdDTO, + TGetAccessPolicyCountByEnvironmentDTO, + TListAccessApprovalPoliciesDTO, + TUpdateAccessApprovalPolicy +} from "./access-approval-policy-types"; -export type TAccessApprovalPolicyDALFactory = ReturnType; +export interface TAccessApprovalPolicyDALFactory + extends Omit, "findById" | "find"> { + find: ( + filter: TFindFilter< + TAccessApprovalPolicies & { + projectId: string; + } + >, + customFilter?: { + policyId?: string; + }, + tx?: Knex + ) => Promise< + { + approvers: ( + | { + id: string | null | undefined; + type: ApproverType.User; + name: string; + sequence: number | null | undefined; + approvalsRequired: number | null | undefined; + } + | { + id: string | null | undefined; + type: ApproverType.Group; + sequence: number | null | undefined; + approvalsRequired: number | null | undefined; + } + )[]; + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + approvals: number; + envId: string; + enforcementLevel: string; + allowedSelfApprovals: boolean; + secretPath?: string | null | undefined; + deletedAt?: Date | null | undefined; + environment: { + id: string; + name: string; + slug: string; + }; + projectId: string; + bypassers: ( + | { + id: string | null | undefined; + type: BypasserType.User; + name: string; + } + | { + id: string | null | undefined; + type: BypasserType.Group; + } + )[]; + }[] + >; + findById: ( + policyId: string, + tx?: Knex + ) => Promise< + | { + approvers: { + id: string | null | undefined; + type: string; + sequence: number | null | undefined; + approvalsRequired: number | null | undefined; + }[]; + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + approvals: number; + envId: string; + enforcementLevel: string; + allowedSelfApprovals: boolean; + secretPath?: string | null | undefined; + deletedAt?: Date | null | undefined; + environment: { + id: string; + name: string; + slug: string; + }; + projectId: string; + } + | undefined + >; + softDeleteById: ( + policyId: string, + tx?: Knex + ) => Promise<{ + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + approvals: number; + envId: string; + enforcementLevel: string; + allowedSelfApprovals: boolean; + secretPath?: string | null | undefined; + deletedAt?: Date | null | undefined; + }>; + findLastValidPolicy: ( + { + envId, + secretPath + }: { + envId: string; + secretPath: string; + }, + tx?: Knex + ) => Promise< + | { + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + approvals: number; + envId: string; + enforcementLevel: string; + allowedSelfApprovals: boolean; + secretPath?: string | null | undefined; + deletedAt?: Date | null | undefined; + } + | undefined + >; +} -export const accessApprovalPolicyDALFactory = (db: TDbClient) => { +export interface TAccessApprovalPolicyServiceFactory { + getAccessPolicyCountByEnvSlug: ({ + actor, + actorOrgId, + actorAuthMethod, + projectSlug, + actorId, + envSlug + }: TGetAccessPolicyCountByEnvironmentDTO) => Promise<{ + count: number; + }>; + createAccessApprovalPolicy: ({ + name, + actor, + actorId, + actorOrgId, + secretPath, + actorAuthMethod, + approvals, + approvers, + bypassers, + projectSlug, + environment, + enforcementLevel, + allowedSelfApprovals, + approvalsRequired + }: TCreateAccessApprovalPolicy) => Promise<{ + environment: { + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + projectId: string; + slug: string; + position: number; + }; + projectId: string; + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + approvals: number; + envId: string; + enforcementLevel: string; + allowedSelfApprovals: boolean; + secretPath?: string | null | undefined; + deletedAt?: Date | null | undefined; + }>; + deleteAccessApprovalPolicy: ({ + policyId, + actor, + actorId, + actorAuthMethod, + actorOrgId + }: TDeleteAccessApprovalPolicy) => Promise<{ + approvers: { + id: string | null | undefined; + type: string; + sequence: number | null | undefined; + approvalsRequired: number | null | undefined; + }[]; + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + approvals: number; + envId: string; + enforcementLevel: string; + allowedSelfApprovals: boolean; + secretPath?: string | null | undefined; + deletedAt?: Date | null | undefined; + environment: { + id: string; + name: string; + slug: string; + }; + projectId: string; + }>; + updateAccessApprovalPolicy: ({ + policyId, + approvers, + bypassers, + secretPath, + name, + actorId, + actor, + actorOrgId, + actorAuthMethod, + approvals, + enforcementLevel, + allowedSelfApprovals, + approvalsRequired + }: TUpdateAccessApprovalPolicy) => Promise<{ + environment: { + id: string; + name: string; + slug: string; + }; + projectId: string; + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + approvals: number; + envId: string; + enforcementLevel: string; + allowedSelfApprovals: boolean; + secretPath?: string | null | undefined; + deletedAt?: Date | null | undefined; + }>; + getAccessApprovalPolicyByProjectSlug: ({ + actorId, + actor, + actorOrgId, + actorAuthMethod, + projectSlug + }: TListAccessApprovalPoliciesDTO) => Promise< + { + approvers: ( + | { + id: string | null | undefined; + type: ApproverType; + name: string; + sequence: number | null | undefined; + approvalsRequired: number | null | undefined; + } + | { + id: string | null | undefined; + type: ApproverType; + sequence: number | null | undefined; + approvalsRequired: number | null | undefined; + } + )[]; + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + approvals: number; + envId: string; + enforcementLevel: string; + allowedSelfApprovals: boolean; + secretPath?: string | null | undefined; + deletedAt?: Date | null | undefined; + environment: { + id: string; + name: string; + slug: string; + }; + projectId: string; + bypassers: ( + | { + id: string | null | undefined; + type: BypasserType; + name: string; + } + | { + id: string | null | undefined; + type: BypasserType; + } + )[]; + }[] + >; + getAccessApprovalPolicyById: ({ + actorId, + actor, + actorOrgId, + actorAuthMethod, + policyId + }: TGetAccessApprovalPolicyByIdDTO) => Promise<{ + approvers: ( + | { + id: string | null | undefined; + type: ApproverType.User; + name: string; + sequence: number | null | undefined; + approvalsRequired: number | null | undefined; + } + | { + id: string | null | undefined; + type: ApproverType.Group; + sequence: number | null | undefined; + approvalsRequired: number | null | undefined; + } + )[]; + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + approvals: number; + envId: string; + enforcementLevel: string; + allowedSelfApprovals: boolean; + secretPath?: string | null | undefined; + deletedAt?: Date | null | undefined; + environment: { + id: string; + name: string; + slug: string; + }; + projectId: string; + bypassers: ( + | { + id: string | null | undefined; + type: BypasserType.User; + name: string; + } + | { + id: string | null | undefined; + type: BypasserType.Group; + } + )[]; + }>; +} + +export const accessApprovalPolicyDALFactory = (db: TDbClient): TAccessApprovalPolicyDALFactory => { const accessApprovalPolicyOrm = ormify(db, TableName.AccessApprovalPolicy); const accessApprovalPolicyFindQuery = async ( @@ -61,7 +411,7 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => { return result; }; - const findById = async (policyId: string, tx?: Knex) => { + const findById: TAccessApprovalPolicyDALFactory["findById"] = async (policyId, tx) => { try { const doc = await accessApprovalPolicyFindQuery(tx || db.replicaNode(), { [`${TableName.AccessApprovalPolicy}.id` as "id"]: policyId @@ -112,13 +462,7 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => { } }; - const find = async ( - filter: TFindFilter, - customFilter?: { - policyId?: string; - }, - tx?: Knex - ) => { + const find: TAccessApprovalPolicyDALFactory["find"] = async (filter, customFilter, tx) => { try { const docs = await accessApprovalPolicyFindQuery(tx || db.replicaNode(), filter, customFilter); @@ -141,7 +485,7 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => { label: "approvers" as const, mapper: ({ approverUserId: id, approverUsername, approverSequence, approvalsRequired }) => ({ id, - type: ApproverType.User, + type: ApproverType.User as const, name: approverUsername, sequence: approverSequence, approvalsRequired @@ -152,7 +496,7 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => { label: "approvers" as const, mapper: ({ approverGroupId: id, approverSequence, approvalsRequired }) => ({ id, - type: ApproverType.Group, + type: ApproverType.Group as const, sequence: approverSequence, approvalsRequired }) @@ -162,7 +506,7 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => { label: "bypassers" as const, mapper: ({ bypasserUserId: id, bypasserUsername }) => ({ id, - type: BypasserType.User, + type: BypasserType.User as const, name: bypasserUsername }) }, @@ -171,7 +515,7 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => { label: "bypassers" as const, mapper: ({ bypasserGroupId: id }) => ({ id, - type: BypasserType.Group + type: BypasserType.Group as const }) } ] @@ -186,12 +530,15 @@ export const accessApprovalPolicyDALFactory = (db: TDbClient) => { } }; - const softDeleteById = async (policyId: string, tx?: Knex) => { + const softDeleteById: TAccessApprovalPolicyDALFactory["softDeleteById"] = async (policyId, tx) => { const softDeletedPolicy = await accessApprovalPolicyOrm.updateById(policyId, { deletedAt: new Date() }, tx); return softDeletedPolicy; }; - const findLastValidPolicy = async ({ envId, secretPath }: { envId: string; secretPath: string }, tx?: Knex) => { + const findLastValidPolicy: TAccessApprovalPolicyDALFactory["findLastValidPolicy"] = async ( + { envId, secretPath }, + tx + ) => { try { const result = await (tx || db.replicaNode())(TableName.AccessApprovalPolicy) .where( diff --git a/backend/src/ee/services/access-approval-policy/access-approval-policy-service.ts b/backend/src/ee/services/access-approval-policy/access-approval-policy-service.ts index 7ff9d65cc..a87994fcb 100644 --- a/backend/src/ee/services/access-approval-policy/access-approval-policy-service.ts +++ b/backend/src/ee/services/access-approval-policy/access-approval-policy-service.ts @@ -24,9 +24,8 @@ import { TAccessApprovalPolicyDALFactory } from "./access-approval-policy-dal"; import { ApproverType, BypasserType, - TCreateAccessApprovalPolicy, + TAccessApprovalPolicyServiceFactory, TDeleteAccessApprovalPolicy, - TGetAccessApprovalPolicyByIdDTO, TGetAccessPolicyCountByEnvironmentDTO, TListAccessApprovalPoliciesDTO, TUpdateAccessApprovalPolicy @@ -48,8 +47,6 @@ type TAccessApprovalPolicyServiceFactoryDep = { orgMembershipDAL: Pick; }; -export type TAccessApprovalPolicyServiceFactory = ReturnType; - export const accessApprovalPolicyServiceFactory = ({ accessApprovalPolicyDAL, accessApprovalPolicyApproverDAL, @@ -63,8 +60,8 @@ export const accessApprovalPolicyServiceFactory = ({ additionalPrivilegeDAL, accessApprovalRequestReviewerDAL, orgMembershipDAL -}: TAccessApprovalPolicyServiceFactoryDep) => { - const createAccessApprovalPolicy = async ({ +}: TAccessApprovalPolicyServiceFactoryDep): TAccessApprovalPolicyServiceFactory => { + const createAccessApprovalPolicy: TAccessApprovalPolicyServiceFactory["createAccessApprovalPolicy"] = async ({ name, actor, actorId, @@ -79,7 +76,7 @@ export const accessApprovalPolicyServiceFactory = ({ enforcementLevel, allowedSelfApprovals, approvalsRequired - }: TCreateAccessApprovalPolicy) => { + }) => { const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` }); @@ -240,31 +237,26 @@ export const accessApprovalPolicyServiceFactory = ({ return { ...accessApproval, environment: env, projectId: project.id }; }; - const getAccessApprovalPolicyByProjectSlug = async ({ - actorId, - actor, - actorOrgId, - actorAuthMethod, - projectSlug - }: TListAccessApprovalPoliciesDTO) => { - const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); - if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` }); + const getAccessApprovalPolicyByProjectSlug: TAccessApprovalPolicyServiceFactory["getAccessApprovalPolicyByProjectSlug"] = + async ({ actorId, actor, actorOrgId, actorAuthMethod, projectSlug }: TListAccessApprovalPoliciesDTO) => { + const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); + if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` }); - // Anyone in the project should be able to get the policies. - await permissionService.getProjectPermission({ - actor, - actorId, - projectId: project.id, - actorAuthMethod, - actorOrgId, - actionProjectType: ActionProjectType.SecretManager - }); + // Anyone in the project should be able to get the policies. + await permissionService.getProjectPermission({ + actor, + actorId, + projectId: project.id, + actorAuthMethod, + actorOrgId, + actionProjectType: ActionProjectType.SecretManager + }); - const accessApprovalPolicies = await accessApprovalPolicyDAL.find({ projectId: project.id, deletedAt: null }); - return accessApprovalPolicies; - }; + const accessApprovalPolicies = await accessApprovalPolicyDAL.find({ projectId: project.id, deletedAt: null }); + return accessApprovalPolicies; + }; - const updateAccessApprovalPolicy = async ({ + const updateAccessApprovalPolicy: TAccessApprovalPolicyServiceFactory["updateAccessApprovalPolicy"] = async ({ policyId, approvers, bypassers, @@ -483,6 +475,7 @@ export const accessApprovalPolicyServiceFactory = ({ return doc; }); + return { ...updatedPolicy, environment: accessApprovalPolicy.environment, @@ -490,7 +483,7 @@ export const accessApprovalPolicyServiceFactory = ({ }; }; - const deleteAccessApprovalPolicy = async ({ + const deleteAccessApprovalPolicy: TAccessApprovalPolicyServiceFactory["deleteAccessApprovalPolicy"] = async ({ policyId, actor, actorId, @@ -539,7 +532,7 @@ export const accessApprovalPolicyServiceFactory = ({ return policy; }; - const getAccessPolicyCountByEnvSlug = async ({ + const getAccessPolicyCountByEnvSlug: TAccessApprovalPolicyServiceFactory["getAccessPolicyCountByEnvSlug"] = async ({ actor, actorOrgId, actorAuthMethod, @@ -576,13 +569,13 @@ export const accessApprovalPolicyServiceFactory = ({ return { count: policies.length }; }; - const getAccessApprovalPolicyById = async ({ + const getAccessApprovalPolicyById: TAccessApprovalPolicyServiceFactory["getAccessApprovalPolicyById"] = async ({ actorId, actor, actorOrgId, actorAuthMethod, policyId - }: TGetAccessApprovalPolicyByIdDTO) => { + }) => { const [policy] = await accessApprovalPolicyDAL.find({}, { policyId }); if (!policy) { diff --git a/backend/src/ee/services/access-approval-policy/access-approval-policy-types.ts b/backend/src/ee/services/access-approval-policy/access-approval-policy-types.ts index bdb50dde1..87a36dde2 100644 --- a/backend/src/ee/services/access-approval-policy/access-approval-policy-types.ts +++ b/backend/src/ee/services/access-approval-policy/access-approval-policy-types.ts @@ -76,3 +76,217 @@ export type TGetAccessApprovalPolicyByIdDTO = { export type TListAccessApprovalPoliciesDTO = { projectSlug: string; } & Omit; + +export interface TAccessApprovalPolicyServiceFactory { + getAccessPolicyCountByEnvSlug: ({ + actor, + actorOrgId, + actorAuthMethod, + projectSlug, + actorId, + envSlug + }: TGetAccessPolicyCountByEnvironmentDTO) => Promise<{ + count: number; + }>; + createAccessApprovalPolicy: ({ + name, + actor, + actorId, + actorOrgId, + secretPath, + actorAuthMethod, + approvals, + approvers, + bypassers, + projectSlug, + environment, + enforcementLevel, + allowedSelfApprovals, + approvalsRequired + }: TCreateAccessApprovalPolicy) => Promise<{ + environment: { + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + projectId: string; + slug: string; + position: number; + }; + projectId: string; + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + approvals: number; + envId: string; + enforcementLevel: string; + allowedSelfApprovals: boolean; + secretPath?: string | null | undefined; + deletedAt?: Date | null | undefined; + }>; + deleteAccessApprovalPolicy: ({ + policyId, + actor, + actorId, + actorAuthMethod, + actorOrgId + }: TDeleteAccessApprovalPolicy) => Promise<{ + approvers: { + id: string | null | undefined; + type: string; + sequence: number | null | undefined; + approvalsRequired: number | null | undefined; + }[]; + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + approvals: number; + envId: string; + enforcementLevel: string; + allowedSelfApprovals: boolean; + secretPath?: string | null | undefined; + deletedAt?: Date | null | undefined; + environment: { + id: string; + name: string; + slug: string; + }; + projectId: string; + }>; + updateAccessApprovalPolicy: ({ + policyId, + approvers, + bypassers, + secretPath, + name, + actorId, + actor, + actorOrgId, + actorAuthMethod, + approvals, + enforcementLevel, + allowedSelfApprovals, + approvalsRequired + }: TUpdateAccessApprovalPolicy) => Promise<{ + environment: { + id: string; + name: string; + slug: string; + }; + projectId: string; + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + approvals: number; + envId: string; + enforcementLevel: string; + allowedSelfApprovals: boolean; + secretPath?: string | null | undefined; + deletedAt?: Date | null | undefined; + }>; + getAccessApprovalPolicyByProjectSlug: ({ + actorId, + actor, + actorOrgId, + actorAuthMethod, + projectSlug + }: TListAccessApprovalPoliciesDTO) => Promise< + { + approvers: ( + | { + id: string | null | undefined; + type: ApproverType; + name: string; + sequence: number | null | undefined; + approvalsRequired: number | null | undefined; + } + | { + id: string | null | undefined; + type: ApproverType; + sequence: number | null | undefined; + approvalsRequired: number | null | undefined; + } + )[]; + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + approvals: number; + envId: string; + enforcementLevel: string; + allowedSelfApprovals: boolean; + secretPath?: string | null | undefined; + deletedAt?: Date | null | undefined; + environment: { + id: string; + name: string; + slug: string; + }; + projectId: string; + bypassers: ( + | { + id: string | null | undefined; + type: BypasserType; + name: string; + } + | { + id: string | null | undefined; + type: BypasserType; + } + )[]; + }[] + >; + getAccessApprovalPolicyById: ({ + actorId, + actor, + actorOrgId, + actorAuthMethod, + policyId + }: TGetAccessApprovalPolicyByIdDTO) => Promise<{ + approvers: ( + | { + id: string | null | undefined; + type: ApproverType.User; + name: string; + sequence: number | null | undefined; + approvalsRequired: number | null | undefined; + } + | { + id: string | null | undefined; + type: ApproverType.Group; + sequence: number | null | undefined; + approvalsRequired: number | null | undefined; + } + )[]; + name: string; + id: string; + createdAt: Date; + updatedAt: Date; + approvals: number; + envId: string; + enforcementLevel: string; + allowedSelfApprovals: boolean; + secretPath?: string | null | undefined; + deletedAt?: Date | null | undefined; + environment: { + id: string; + name: string; + slug: string; + }; + projectId: string; + bypassers: ( + | { + id: string | null | undefined; + type: BypasserType.User; + name: string; + } + | { + id: string | null | undefined; + type: BypasserType.Group; + } + )[]; + }>; +} diff --git a/backend/src/services/pki-templates/pki-templates-dal.ts b/backend/src/services/pki-templates/pki-templates-dal.ts index 4f618c807..81fffb0e8 100644 --- a/backend/src/services/pki-templates/pki-templates-dal.ts +++ b/backend/src/services/pki-templates/pki-templates-dal.ts @@ -91,7 +91,7 @@ export const pkiTemplatesDALFactory = (db: TDbClient) => { void query.orderBy(sort.map(([column, order, nulls]) => ({ column: column as string, order, nulls }))); } - const res = await query; + const res = (await query) as Array[0] & { count: string }>; return res.map((el) => ({ ...el, ca: { id: el.caId, name: el.caName } })); } catch (error) { throw new DatabaseError({ error, name: "Find one" }); diff --git a/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts b/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts index 1adfac22c..01718d570 100644 --- a/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts +++ b/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts @@ -561,7 +561,7 @@ const formatMultiValueEnv = (val?: string) => { return `"${val.replaceAll("\n", "\\n")}"`; }; -type TSecretReferenceTraceNode = { +export type TSecretReferenceTraceNode = { key: string; value?: string; environment: string;