From 8b25f202fe4d6b3069ca65d0ffd222561ba339f9 Mon Sep 17 00:00:00 2001 From: x032205 Date: Mon, 19 May 2025 21:28:18 -0400 Subject: [PATCH] feat(policies): Specific permission for bypassing policy --- .../access-approval-policy-service.ts | 16 ++- .../ee/services/permission/default-roles.ts | 17 ++- .../services/permission/project-permission.ts | 14 ++- .../secret-approval-policy-service.ts | 25 +++- .../secret-approval-request-service.ts | 16 ++- .../permissions/project-permissions.mdx | 13 +- .../ProjectPermissionContext/index.tsx | 3 +- .../context/ProjectPermissionContext/types.ts | 10 +- frontend/src/context/index.tsx | 3 +- .../ProjectRoleModifySection.utils.tsx | 42 +++++-- .../ApprovalPolicyList/ApprovalPolicyList.tsx | 15 ++- .../components/AccessPolicyModal.tsx | 112 +++++++----------- .../components/ApprovalPolicyRow.tsx | 5 +- .../SecretApprovalRequestAction.tsx | 13 +- 14 files changed, 193 insertions(+), 111 deletions(-) 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 6b5014acc2..17176162b1 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 @@ -2,7 +2,7 @@ import { ForbiddenError } from "@casl/ability"; import { ActionProjectType } from "@app/db/schemas"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; +import { ProjectPermissionApprovalActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors"; import { TProjectDALFactory } from "@app/services/project/project-dal"; import { TProjectEnvDALFactory } from "@app/services/project-env/project-env-dal"; @@ -98,7 +98,7 @@ export const accessApprovalPolicyServiceFactory = ({ }); ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, + ProjectPermissionApprovalActions.Create, ProjectPermissionSub.SecretApproval ); const env = await projectEnvDAL.findOne({ slug: environment, projectId: project.id }); @@ -256,7 +256,10 @@ export const accessApprovalPolicyServiceFactory = ({ actionProjectType: ActionProjectType.SecretManager }); - ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretApproval); + ForbiddenError.from(permission).throwUnlessCan( + ProjectPermissionApprovalActions.Edit, + ProjectPermissionSub.SecretApproval + ); const updatedPolicy = await accessApprovalPolicyDAL.transaction(async (tx) => { const doc = await accessApprovalPolicyDAL.updateById( @@ -341,7 +344,7 @@ export const accessApprovalPolicyServiceFactory = ({ actionProjectType: ActionProjectType.SecretManager }); ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Delete, + ProjectPermissionApprovalActions.Delete, ProjectPermissionSub.SecretApproval ); @@ -432,7 +435,10 @@ export const accessApprovalPolicyServiceFactory = ({ actionProjectType: ActionProjectType.SecretManager }); - ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval); + ForbiddenError.from(permission).throwUnlessCan( + ProjectPermissionApprovalActions.Read, + ProjectPermissionSub.SecretApproval + ); return policy; }; diff --git a/backend/src/ee/services/permission/default-roles.ts b/backend/src/ee/services/permission/default-roles.ts index a018ffe818..9461227da5 100644 --- a/backend/src/ee/services/permission/default-roles.ts +++ b/backend/src/ee/services/permission/default-roles.ts @@ -2,6 +2,7 @@ import { AbilityBuilder, createMongoAbility, MongoAbility } from "@casl/ability" import { ProjectPermissionActions, + ProjectPermissionApprovalActions, ProjectPermissionCertificateActions, ProjectPermissionCmekActions, ProjectPermissionDynamicSecretActions, @@ -25,7 +26,6 @@ const buildAdminPermissionRules = () => { [ ProjectPermissionSub.SecretFolders, ProjectPermissionSub.SecretImports, - ProjectPermissionSub.SecretApproval, ProjectPermissionSub.Role, ProjectPermissionSub.Integrations, ProjectPermissionSub.Webhooks, @@ -55,6 +55,17 @@ const buildAdminPermissionRules = () => { ); }); + can( + [ + ProjectPermissionApprovalActions.Read, + ProjectPermissionApprovalActions.Edit, + ProjectPermissionApprovalActions.Create, + ProjectPermissionApprovalActions.Delete, + ProjectPermissionApprovalActions.AllowChangeBypass + ], + ProjectPermissionSub.SecretApproval + ); + can( [ ProjectPermissionCertificateActions.Read, @@ -243,7 +254,7 @@ const buildMemberPermissionRules = () => { ProjectPermissionSub.SecretImports ); - can([ProjectPermissionActions.Read], ProjectPermissionSub.SecretApproval); + can([ProjectPermissionApprovalActions.Read], ProjectPermissionSub.SecretApproval); can([ProjectPermissionSecretRotationActions.Read], ProjectPermissionSub.SecretRotation); can([ProjectPermissionActions.Read, ProjectPermissionActions.Create], ProjectPermissionSub.SecretRollback); @@ -391,7 +402,7 @@ const buildViewerPermissionRules = () => { can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretFolders); can(ProjectPermissionDynamicSecretActions.ReadRootCredential, ProjectPermissionSub.DynamicSecrets); can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretImports); - can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval); + can(ProjectPermissionApprovalActions.Read, ProjectPermissionSub.SecretApproval); can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback); can(ProjectPermissionSecretRotationActions.Read, ProjectPermissionSub.SecretRotation); can(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member); diff --git a/backend/src/ee/services/permission/project-permission.ts b/backend/src/ee/services/permission/project-permission.ts index 5474facf66..27cd338553 100644 --- a/backend/src/ee/services/permission/project-permission.ts +++ b/backend/src/ee/services/permission/project-permission.ts @@ -34,6 +34,14 @@ export enum ProjectPermissionSecretActions { Delete = "delete" } +export enum ProjectPermissionApprovalActions { + Read = "read", + Create = "create", + Edit = "edit", + Delete = "delete", + AllowChangeBypass = "allow-change-bypass" +} + export enum ProjectPermissionCmekActions { Read = "read", Create = "create", @@ -242,7 +250,7 @@ export type ProjectPermissionSet = | [ProjectPermissionActions, ProjectPermissionSub.IpAllowList] | [ProjectPermissionActions, ProjectPermissionSub.Settings] | [ProjectPermissionActions, ProjectPermissionSub.ServiceTokens] - | [ProjectPermissionActions, ProjectPermissionSub.SecretApproval] + | [ProjectPermissionApprovalActions, ProjectPermissionSub.SecretApproval] | [ ProjectPermissionSecretRotationActions, ( @@ -439,7 +447,7 @@ const PkiSubscriberConditionSchema = z const GeneralPermissionSchema = [ z.object({ subject: z.literal(ProjectPermissionSub.SecretApproval).describe("The entity this permission pertains to."), - action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe( + action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionApprovalActions).describe( "Describe what action an entity can take." ) }), @@ -605,7 +613,7 @@ const GeneralPermissionSchema = [ }) ]; -// Do not update this schema anymore, as it's kept purely for backwards compatability. Update V2 schema only. +// Do not update this schema anymore, as it's kept purely for backwards compatibility. Update V2 schema only. export const ProjectPermissionV1Schema = z.discriminatedUnion("subject", [ z.object({ subject: z.literal(ProjectPermissionSub.Secrets).describe("The entity this permission pertains to."), diff --git a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-service.ts b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-service.ts index 4c212e6cd5..7305ab645c 100644 --- a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-service.ts +++ b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-service.ts @@ -3,7 +3,11 @@ import picomatch from "picomatch"; import { ActionProjectType } from "@app/db/schemas"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; -import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; +import { + ProjectPermissionActions, + ProjectPermissionApprovalActions, + ProjectPermissionSub +} from "@app/ee/services/permission/project-permission"; import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { removeTrailingSlash } from "@app/lib/fn"; import { containsGlobPatterns } from "@app/lib/picomatch"; @@ -89,7 +93,7 @@ export const secretApprovalPolicyServiceFactory = ({ actionProjectType: ActionProjectType.SecretManager }); ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Create, + ProjectPermissionApprovalActions.Create, ProjectPermissionSub.SecretApproval ); @@ -204,7 +208,10 @@ export const secretApprovalPolicyServiceFactory = ({ actorOrgId, actionProjectType: ActionProjectType.SecretManager }); - ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretApproval); + ForbiddenError.from(permission).throwUnlessCan( + ProjectPermissionApprovalActions.Edit, + ProjectPermissionSub.SecretApproval + ); const plan = await licenseService.getPlan(actorOrgId); if (!plan.secretApproval) { @@ -301,7 +308,7 @@ export const secretApprovalPolicyServiceFactory = ({ actionProjectType: ActionProjectType.SecretManager }); ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Delete, + ProjectPermissionApprovalActions.Delete, ProjectPermissionSub.SecretApproval ); @@ -340,7 +347,10 @@ export const secretApprovalPolicyServiceFactory = ({ actorOrgId, actionProjectType: ActionProjectType.SecretManager }); - ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval); + ForbiddenError.from(permission).throwUnlessCan( + ProjectPermissionApprovalActions.Read, + ProjectPermissionSub.SecretApproval + ); const sapPolicies = await secretApprovalPolicyDAL.find({ projectId, deletedAt: null }); return sapPolicies; @@ -413,7 +423,10 @@ export const secretApprovalPolicyServiceFactory = ({ actionProjectType: ActionProjectType.SecretManager }); - ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval); + ForbiddenError.from(permission).throwUnlessCan( + ProjectPermissionApprovalActions.Read, + ProjectPermissionSub.SecretApproval + ); return sapPolicy; }; diff --git a/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts b/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts index 262e8e5cfd..500312a7ac 100644 --- a/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts +++ b/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts @@ -62,7 +62,11 @@ import { TUserDALFactory } from "@app/services/user/user-dal"; import { TLicenseServiceFactory } from "../license/license-service"; import { throwIfMissingSecretReadValueOrDescribePermission } from "../permission/permission-fns"; import { TPermissionServiceFactory } from "../permission/permission-service"; -import { ProjectPermissionSecretActions, ProjectPermissionSub } from "../permission/project-permission"; +import { + ProjectPermissionApprovalActions, + ProjectPermissionSecretActions, + ProjectPermissionSub +} from "../permission/project-permission"; import { TSecretApprovalPolicyDALFactory } from "../secret-approval-policy/secret-approval-policy-dal"; import { TSecretSnapshotServiceFactory } from "../secret-snapshot/secret-snapshot-service"; import { TSecretApprovalRequestDALFactory } from "./secret-approval-request-dal"; @@ -504,7 +508,7 @@ export const secretApprovalRequestServiceFactory = ({ }); } - const { hasRole } = await permissionService.getProjectPermission({ + const { hasRole, permission } = await permissionService.getProjectPermission({ actor: ActorType.USER, actorId, projectId, @@ -531,7 +535,13 @@ export const secretApprovalRequestServiceFactory = ({ ).length; const isSoftEnforcement = secretApprovalRequest.policy.enforcementLevel === EnforcementLevel.Soft; - if (!hasMinApproval && !isSoftEnforcement) + if ( + !hasMinApproval && + !( + isSoftEnforcement && + permission.can(ProjectPermissionApprovalActions.AllowChangeBypass, ProjectPermissionSub.SecretApproval) + ) + ) throw new BadRequestError({ message: "Doesn't have minimum approvals needed" }); const { botKey, shouldUseSecretV2Bridge, project } = await projectBotService.getBotKey(projectId); diff --git a/docs/internals/permissions/project-permissions.mdx b/docs/internals/permissions/project-permissions.mdx index acf95485b3..dabe0e7868 100644 --- a/docs/internals/permissions/project-permissions.mdx +++ b/docs/internals/permissions/project-permissions.mdx @@ -178,12 +178,13 @@ Supports conditions and permission inversion #### Subject: `secret-approval` -| Action | Description | -| -------- | ----------------------------------- | -| `read` | View approval policies and requests | -| `create` | Create new approval policies | -| `edit` | Modify approval policies | -| `delete` | Remove approval policies | +| Action | Description | +| --------------------- | ---------------------------------------------------------------------------- | +| `read` | View approval policies and requests | +| `create` | Create new approval policies | +| `edit` | Modify approval policies | +| `delete` | Remove approval policies | +| `allow-change-bypass` | Allow request creators to bypass policy in break-glass situations | #### Subject: `secret-rotation` diff --git a/frontend/src/context/ProjectPermissionContext/index.tsx b/frontend/src/context/ProjectPermissionContext/index.tsx index d7b7334ea8..9662ffd1b7 100644 --- a/frontend/src/context/ProjectPermissionContext/index.tsx +++ b/frontend/src/context/ProjectPermissionContext/index.tsx @@ -11,5 +11,6 @@ export { ProjectPermissionMemberActions, ProjectPermissionPkiSubscriberActions, ProjectPermissionSshHostActions, - ProjectPermissionSub + ProjectPermissionSub, + ProjectPermissionApprovalActions } from "./types"; diff --git a/frontend/src/context/ProjectPermissionContext/types.ts b/frontend/src/context/ProjectPermissionContext/types.ts index a640f6eaab..96ad12ac31 100644 --- a/frontend/src/context/ProjectPermissionContext/types.ts +++ b/frontend/src/context/ProjectPermissionContext/types.ts @@ -24,6 +24,14 @@ export enum ProjectPermissionSecretActions { Delete = "delete" } +export enum ProjectPermissionApprovalActions { + Read = "read", + Create = "create", + Edit = "edit", + Delete = "delete", + AllowChangeBypass = "allow-change-bypass" +} + export enum ProjectPermissionDynamicSecretActions { ReadRootCredential = "read-root-credential", CreateRootCredential = "create-root-credential", @@ -285,7 +293,7 @@ export type ProjectPermissionSet = | [ProjectPermissionActions, ProjectPermissionSub.IpAllowList] | [ProjectPermissionActions, ProjectPermissionSub.Settings] | [ProjectPermissionActions, ProjectPermissionSub.ServiceTokens] - | [ProjectPermissionActions, ProjectPermissionSub.SecretApproval] + | [ProjectPermissionApprovalActions, ProjectPermissionSub.SecretApproval] | [ ProjectPermissionIdentityActions, ( diff --git a/frontend/src/context/index.tsx b/frontend/src/context/index.tsx index 91fcd90556..80ae7efa5b 100644 --- a/frontend/src/context/index.tsx +++ b/frontend/src/context/index.tsx @@ -20,7 +20,8 @@ export { ProjectPermissionPkiSubscriberActions, ProjectPermissionSshHostActions, ProjectPermissionSub, - useProjectPermission + useProjectPermission, + ProjectPermissionApprovalActions } from "./ProjectPermissionContext"; export { useServerConfig } from "./ServerConfigContext"; export { useSubscription } from "./SubscriptionContext"; diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx index e4b9ed3024..cb3cd015d8 100644 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx @@ -12,6 +12,7 @@ import { } from "@app/context"; import { PermissionConditionOperators, + ProjectPermissionApprovalActions, ProjectPermissionDynamicSecretActions, ProjectPermissionGroupActions, ProjectPermissionIdentityActions, @@ -52,6 +53,14 @@ const SecretPolicyActionSchema = z.object({ [ProjectPermissionSecretActions.Create]: z.boolean().optional() }); +const ApprovalPolicyActionSchema = z.object({ + [ProjectPermissionApprovalActions.Read]: z.boolean().optional(), + [ProjectPermissionApprovalActions.Edit]: z.boolean().optional(), + [ProjectPermissionApprovalActions.Delete]: z.boolean().optional(), + [ProjectPermissionApprovalActions.Create]: z.boolean().optional(), + [ProjectPermissionApprovalActions.AllowChangeBypass]: z.boolean().optional() +}); + const CmekPolicyActionSchema = z.object({ read: z.boolean().optional(), edit: z.boolean().optional(), @@ -261,7 +270,7 @@ export const projectRoleFormSchema = z.object({ .array() .default([]), [ProjectPermissionSub.SshHostGroups]: GeneralPolicyActionSchema.array().default([]), - [ProjectPermissionSub.SecretApproval]: GeneralPolicyActionSchema.array().default([]), + [ProjectPermissionSub.SecretApproval]: ApprovalPolicyActionSchema.array().default([]), [ProjectPermissionSub.SecretRollback]: SecretRollbackPolicyActionSchema.array().default([]), [ProjectPermissionSub.Project]: WorkspacePolicyActionSchema.array().default([]), [ProjectPermissionSub.Tags]: GeneralPolicyActionSchema.array().default([]), @@ -402,7 +411,6 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => { ProjectPermissionSub.PkiAlerts, ProjectPermissionSub.PkiCollections, ProjectPermissionSub.CertificateTemplates, - ProjectPermissionSub.SecretApproval, ProjectPermissionSub.Tags, ProjectPermissionSub.SecretRotation, ProjectPermissionSub.Kms, @@ -564,6 +572,25 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => { return; } + if (subject === ProjectPermissionSub.SecretApproval) { + const canCreate = action.includes(ProjectPermissionApprovalActions.Create); + const canDelete = action.includes(ProjectPermissionApprovalActions.Delete); + const canEdit = action.includes(ProjectPermissionApprovalActions.Edit); + const canRead = action.includes(ProjectPermissionApprovalActions.Read); + const canChangeBypass = action.includes(ProjectPermissionApprovalActions.AllowChangeBypass); + + if (!formVal[subject]) formVal[subject] = [{}]; + + // Map actions to the keys defined in ApprovalPolicyActionSchema + if (canCreate) formVal[subject]![0][ProjectPermissionApprovalActions.Create] = true; + if (canDelete) formVal[subject]![0][ProjectPermissionApprovalActions.Delete] = true; + if (canEdit) formVal[subject]![0][ProjectPermissionApprovalActions.Edit] = true; + if (canRead) formVal[subject]![0][ProjectPermissionApprovalActions.Read] = true; + if (canChangeBypass) + formVal[subject]![0][ProjectPermissionApprovalActions.AllowChangeBypass] = true; + return; + } + if (subject === ProjectPermissionSub.SecretRollback) { const canRead = action.includes(ProjectPermissionActions.Read); const canCreate = action.includes(ProjectPermissionActions.Create); @@ -1181,10 +1208,11 @@ export const PROJECT_PERMISSION_OBJECT: TProjectPermissionObject = { [ProjectPermissionSub.SecretApproval]: { title: "Secret Approval Policies", actions: [ - { label: "Read", value: "read" }, - { label: "Create", value: "create" }, - { label: "Modify", value: "edit" }, - { label: "Remove", value: "delete" } + { label: "Read", value: ProjectPermissionApprovalActions.Read }, + { label: "Create", value: ProjectPermissionApprovalActions.Create }, + { label: "Modify", value: ProjectPermissionApprovalActions.Edit }, + { label: "Remove", value: ProjectPermissionApprovalActions.Delete }, + { label: "Allow Change Bypass", value: ProjectPermissionApprovalActions.AllowChangeBypass } ] }, [ProjectPermissionSub.SecretRotation]: { @@ -1661,7 +1689,7 @@ export const RoleTemplates: Record = { }, { subject: ProjectPermissionSub.SecretApproval, - actions: Object.values(ProjectPermissionActions) + actions: Object.values(ProjectPermissionApprovalActions) }, { subject: ProjectPermissionSub.ServiceTokens, diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/ApprovalPolicyList.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/ApprovalPolicyList.tsx index 8e03c99740..9cdf36e0a3 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/ApprovalPolicyList.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/ApprovalPolicyList.tsx @@ -50,6 +50,7 @@ import { TAccessApprovalPolicy, Workspace } from "@app/hooks/api/types"; import { AccessPolicyForm } from "./components/AccessPolicyModal"; import { ApprovalPolicyRow } from "./components/ApprovalPolicyRow"; +import { ProjectPermissionApprovalActions } from "@app/context/ProjectPermissionContext/types"; interface IProps { workspaceId: string; @@ -61,8 +62,10 @@ const useApprovalPolicies = (permission: TProjectPermission, currentWorkspace?: projectSlug: currentWorkspace?.slug as string, options: { enabled: - permission.can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval) && - !!currentWorkspace?.slug + permission.can( + ProjectPermissionApprovalActions.Read, + ProjectPermissionSub.SecretApproval + ) && !!currentWorkspace?.slug } } ); @@ -71,8 +74,10 @@ const useApprovalPolicies = (permission: TProjectPermission, currentWorkspace?: workspaceId: currentWorkspace?.id as string, options: { enabled: - permission.can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval) && - !!currentWorkspace?.id + permission.can( + ProjectPermissionApprovalActions.Read, + ProjectPermissionSub.SecretApproval + ) && !!currentWorkspace?.id } } ); @@ -160,7 +165,7 @@ export const ApprovalPolicyList = ({ workspaceId }: IProps) => {
{(isAllowed) => ( diff --git a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/AccessPolicyModal.tsx b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/AccessPolicyModal.tsx index a9304e7edc..fa78d4179d 100644 --- a/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/AccessPolicyModal.tsx +++ b/frontend/src/pages/secret-manager/SecretApprovalsPage/components/ApprovalPolicyList/components/AccessPolicyModal.tsx @@ -303,73 +303,6 @@ export const AccessPolicyForm = ({ )} /> - ( - -

- Determines the level of enforcement for required approvers of a request: -

-

- Hard enforcement requires at least{" "} - {approversRequired} approver(s) to - approve the request.` -

-

- Soft enforcement At least{" "} - {approversRequired} approver(s) must - approve the request; however, the requester can bypass approval - requirements in emergencies. -

- - } - > - -
- )} - /> - - ( - - option.slug} - getOptionLabel={(option) => option.name} - /> - - )} - />
+ ( + + option.slug} + getOptionLabel={(option) => option.name} + /> + + )} + />

Approvers

@@ -465,6 +420,29 @@ export const AccessPolicyForm = ({ )} /> + ( + + + onChange(v ? EnforcementLevel.Soft : EnforcementLevel.Hard) + } + > + Allow request creators to bypass policy in break-glass situations + + + )} + />