diff --git a/backend/src/db/migrations/20240717194958_add-enforcement-level-access-policies.ts b/backend/src/db/migrations/20240717194958_add-enforcement-level-access-policies.ts new file mode 100644 index 000000000..9aeb8d51e --- /dev/null +++ b/backend/src/db/migrations/20240717194958_add-enforcement-level-access-policies.ts @@ -0,0 +1,15 @@ +import { Knex } from "knex"; + +import { EnforcementLevel } from "@app/lib/types"; + +export async function up(knex: Knex): Promise { + await knex.schema.table("access_approval_policies", (table) => { + table.specificType("enforcementLevel", "VARCHAR(10)").notNullable().defaultTo(EnforcementLevel.Hard); + }); +} + +export async function down(knex: Knex): Promise { + await knex.schema.table("access_approval_policies", (table) => { + table.dropColumn("enforcementLevel"); + }); +} diff --git a/backend/src/db/schemas/access-approval-policies.ts b/backend/src/db/schemas/access-approval-policies.ts index 69068d23b..c05f22b31 100644 --- a/backend/src/db/schemas/access-approval-policies.ts +++ b/backend/src/db/schemas/access-approval-policies.ts @@ -5,6 +5,8 @@ import { z } from "zod"; +import { EnforcementLevel } from "@app/lib/types"; + import { TImmutableDBKeys } from "./models"; export const AccessApprovalPoliciesSchema = z.object({ @@ -14,7 +16,8 @@ export const AccessApprovalPoliciesSchema = z.object({ secretPath: z.string().nullable().optional(), envId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date() + updatedAt: z.date(), + enforcementLevel: z.nativeEnum(EnforcementLevel).default(EnforcementLevel.Hard) }); export type TAccessApprovalPolicies = z.infer; diff --git a/backend/src/ee/routes/v1/access-approval-policy-router.ts b/backend/src/ee/routes/v1/access-approval-policy-router.ts index 3b8949d3b..fe3a16f2b 100644 --- a/backend/src/ee/routes/v1/access-approval-policy-router.ts +++ b/backend/src/ee/routes/v1/access-approval-policy-router.ts @@ -1,6 +1,7 @@ import { nanoid } from "nanoid"; import { z } from "zod"; +import { EnforcementLevel } from "@app/lib/types"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { sapPubSchema } from "@app/server/routes/sanitizedSchemas"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -17,7 +18,8 @@ export const registerAccessApprovalPolicyRouter = async (server: FastifyZodProvi secretPath: z.string().trim().default("/"), environment: z.string(), approvers: z.string().array().min(1), - approvals: z.number().min(1).default(1) + approvals: z.number().min(1).default(1), + enforcementLevel: z.nativeEnum(EnforcementLevel) }) .refine((data) => data.approvals <= data.approvers.length, { path: ["approvals"], @@ -38,7 +40,8 @@ export const registerAccessApprovalPolicyRouter = async (server: FastifyZodProvi actorOrgId: req.permission.orgId, ...req.body, projectSlug: req.body.projectSlug, - name: req.body.name ?? `${req.body.environment}-${nanoid(3)}` + name: req.body.name ?? `${req.body.environment}-${nanoid(3)}`, + enforcementLevel: req.body.enforcementLevel }); return { approval }; } @@ -115,7 +118,8 @@ export const registerAccessApprovalPolicyRouter = async (server: FastifyZodProvi .optional() .transform((val) => (val === "" ? "/" : val)), approvers: z.string().array().min(1), - approvals: z.number().min(1).default(1) + approvals: z.number().min(1).default(1), + enforcementLevel: z.nativeEnum(EnforcementLevel) }) .refine((data) => data.approvals <= data.approvers.length, { path: ["approvals"], 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 51a51abb5..c91fbf970 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 @@ -47,7 +47,8 @@ export const accessApprovalPolicyServiceFactory = ({ approvals, approvers, projectSlug, - environment + environment, + enforcementLevel }: TCreateAccessApprovalPolicy) => { const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); if (!project) throw new BadRequestError({ message: "Project not found" }); @@ -94,7 +95,8 @@ export const accessApprovalPolicyServiceFactory = ({ envId: env.id, approvals, secretPath, - name + name, + enforcementLevel }, tx ); @@ -143,7 +145,8 @@ export const accessApprovalPolicyServiceFactory = ({ actor, actorOrgId, actorAuthMethod, - approvals + approvals, + enforcementLevel }: TUpdateAccessApprovalPolicy) => { const accessApprovalPolicy = await accessApprovalPolicyDAL.findById(policyId); if (!accessApprovalPolicy) throw new BadRequestError({ message: "Secret approval policy not found" }); @@ -163,7 +166,8 @@ export const accessApprovalPolicyServiceFactory = ({ { approvals, secretPath, - name + name, + enforcementLevel }, tx ); 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 601561b68..fdb6fc8bb 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 @@ -1,4 +1,4 @@ -import { TProjectPermission } from "@app/lib/types"; +import { EnforcementLevel, TProjectPermission } from "@app/lib/types"; import { ActorAuthMethod } from "@app/services/auth/auth-type"; import { TPermissionServiceFactory } from "../permission/permission-service"; @@ -20,6 +20,7 @@ export type TCreateAccessApprovalPolicy = { approvers: string[]; projectSlug: string; name: string; + enforcementLevel: EnforcementLevel; } & Omit; export type TUpdateAccessApprovalPolicy = { @@ -28,6 +29,7 @@ export type TUpdateAccessApprovalPolicy = { approvers?: string[]; secretPath?: string; name?: string; + enforcementLevel?: EnforcementLevel; } & Omit; export type TDeleteAccessApprovalPolicy = {