Merge pull request #3057 from akhilmhdh/fix/permission-scope

Permission boundary check
This commit is contained in:
Maidul Islam
2025-03-09 22:25:16 -04:00
committed by GitHub
27 changed files with 1308 additions and 183 deletions
@@ -4,7 +4,7 @@ import ms from "ms";
import { ActionProjectType, ProjectMembershipRole, SecretKeyEncoding, TGroups } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { validatePermissionBoundary } from "@app/lib/casl/boundary";
import { decryptAsymmetric, encryptAsymmetric } from "@app/lib/crypto";
import { infisicalSymmetricDecrypt } from "@app/lib/crypto/encryption";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
@@ -102,11 +102,13 @@ export const groupProjectServiceFactory = ({
project.id
);
const hasRequiredPrivileges = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasRequiredPrivileges) {
throw new ForbiddenRequestError({ message: "Failed to assign group to a more privileged role" });
}
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
name: "PermissionBoundaryError",
message: "Failed to assign group to a more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
}
// validate custom roles input
@@ -267,12 +269,13 @@ export const groupProjectServiceFactory = ({
requestedRoleChange,
project.id
);
const hasRequiredPrivileges = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasRequiredPrivileges) {
throw new ForbiddenRequestError({ message: "Failed to assign group to a more privileged role" });
}
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
name: "PermissionBoundaryError",
message: "Failed to assign group to a more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
}
// validate custom roles input
@@ -7,7 +7,7 @@ import { IdentityAuthMethod } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { validatePermissionBoundary } from "@app/lib/casl/boundary";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError, ForbiddenRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
@@ -339,9 +339,12 @@ export const identityAwsAuthServiceFactory = ({
actorOrgId
);
if (!isAtLeastAsPrivileged(permission, rolePermission))
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: "Failed to revoke aws auth of identity with more privileged role"
name: "PermissionBoundaryError",
message: "Failed to revoke aws auth of identity with more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
const revokedIdentityAwsAuth = await identityAwsAuthDAL.transaction(async (tx) => {
@@ -5,7 +5,7 @@ import { IdentityAuthMethod } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { validatePermissionBoundary } from "@app/lib/casl/boundary";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError, ForbiddenRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
@@ -312,9 +312,12 @@ export const identityAzureAuthServiceFactory = ({
actorAuthMethod,
actorOrgId
);
if (!isAtLeastAsPrivileged(permission, rolePermission))
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: "Failed to revoke azure auth of identity with more privileged role"
name: "PermissionBoundaryError",
message: "Failed to revoke azure auth of identity with more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
const revokedIdentityAzureAuth = await identityAzureAuthDAL.transaction(async (tx) => {
@@ -5,7 +5,7 @@ import { IdentityAuthMethod } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { validatePermissionBoundary } from "@app/lib/casl/boundary";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError, ForbiddenRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
@@ -358,9 +358,12 @@ export const identityGcpAuthServiceFactory = ({
actorAuthMethod,
actorOrgId
);
if (!isAtLeastAsPrivileged(permission, rolePermission))
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: "Failed to revoke gcp auth of identity with more privileged role"
name: "PermissionBoundaryError",
message: "Failed to revoke gcp auth of identity with more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
const revokedIdentityGcpAuth = await identityGcpAuthDAL.transaction(async (tx) => {
@@ -7,7 +7,7 @@ import { IdentityAuthMethod, TIdentityJwtAuthsUpdate } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { validatePermissionBoundary } from "@app/lib/casl/boundary";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError, ForbiddenRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
@@ -508,11 +508,13 @@ export const identityJwtAuthServiceFactory = ({
actorOrgId
);
if (!isAtLeastAsPrivileged(permission, rolePermission)) {
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: "Failed to revoke JWT auth of identity with more privileged role"
name: "PermissionBoundaryError",
message: "Failed to revoke jwt auth of identity with more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
}
const revokedIdentityJwtAuth = await identityJwtAuthDAL.transaction(async (tx) => {
const deletedJwtAuth = await identityJwtAuthDAL.delete({ identityId }, tx);
@@ -7,7 +7,7 @@ import { IdentityAuthMethod, TIdentityKubernetesAuthsUpdate } from "@app/db/sche
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { validatePermissionBoundary } from "@app/lib/casl/boundary";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError, ForbiddenRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
@@ -487,9 +487,12 @@ export const identityKubernetesAuthServiceFactory = ({
actorAuthMethod,
actorOrgId
);
if (!isAtLeastAsPrivileged(permission, rolePermission))
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: "Failed to revoke kubernetes auth of identity with more privileged role"
name: "PermissionBoundaryError",
message: "Failed to revoke kubernetes auth of identity with more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
const revokedIdentityKubernetesAuth = await identityKubernetesAuthDAL.transaction(async (tx) => {
@@ -8,7 +8,7 @@ import { IdentityAuthMethod, TIdentityOidcAuthsUpdate } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { validatePermissionBoundary } from "@app/lib/casl/boundary";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError, ForbiddenRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
@@ -428,11 +428,13 @@ export const identityOidcAuthServiceFactory = ({
actorOrgId
);
if (!isAtLeastAsPrivileged(permission, rolePermission)) {
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: "Failed to revoke OIDC auth of identity with more privileged role"
name: "PermissionBoundaryError",
message: "Failed to revoke oidc auth of identity with more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
}
const revokedIdentityOidcAuth = await identityOidcAuthDAL.transaction(async (tx) => {
const deletedOidcAuth = await identityOidcAuthDAL.delete({ identityId }, tx);
@@ -4,7 +4,7 @@ import ms from "ms";
import { ActionProjectType, ProjectMembershipRole } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { validatePermissionBoundary } from "@app/lib/casl/boundary";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { groupBy } from "@app/lib/fn";
@@ -91,11 +91,13 @@ export const identityProjectServiceFactory = ({
projectId
);
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasRequiredPriviledges) {
throw new ForbiddenRequestError({ message: "Failed to change to a more privileged role" });
}
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
name: "PermissionBoundaryError",
message: "Failed to assign to a more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
}
// validate custom roles input
@@ -185,9 +187,13 @@ export const identityProjectServiceFactory = ({
projectId
);
if (!isAtLeastAsPrivileged(permission, rolePermission)) {
throw new ForbiddenRequestError({ message: "Failed to change to a more privileged role" });
}
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
name: "PermissionBoundaryError",
message: "Failed to change to a more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
}
// validate custom roles input
@@ -277,8 +283,13 @@ export const identityProjectServiceFactory = ({
actorOrgId,
actionProjectType: ActionProjectType.Any
});
if (!isAtLeastAsPrivileged(permission, identityRolePermission))
throw new ForbiddenRequestError({ message: "Failed to delete more privileged identity" });
const permissionBoundary = validatePermissionBoundary(permission, identityRolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
name: "PermissionBoundaryError",
message: "Failed to remove more privileged identity",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
const [deletedIdentity] = await identityProjectDAL.delete({ identityId, projectId });
return deletedIdentity;
@@ -5,7 +5,7 @@ import { IdentityAuthMethod, TableName } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { validatePermissionBoundary } from "@app/lib/casl/boundary";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
@@ -245,11 +245,13 @@ export const identityTokenAuthServiceFactory = ({
actorOrgId
);
if (!isAtLeastAsPrivileged(permission, rolePermission)) {
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: "Failed to revoke Token Auth of identity with more privileged role"
name: "PermissionBoundaryError",
message: "Failed to revoke token auth of identity with more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
}
const revokedIdentityTokenAuth = await identityTokenAuthDAL.transaction(async (tx) => {
const deletedTokenAuth = await identityTokenAuthDAL.delete({ identityId }, tx);
@@ -295,10 +297,12 @@ export const identityTokenAuthServiceFactory = ({
actorAuthMethod,
actorOrgId
);
const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasPriviledge)
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: "Failed to create token for identity with more privileged role"
name: "PermissionBoundaryError",
message: "Failed to create token for identity with more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
const identityTokenAuth = await identityTokenAuthDAL.findOne({ identityId });
@@ -415,10 +419,12 @@ export const identityTokenAuthServiceFactory = ({
actorAuthMethod,
actorOrgId
);
const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasPriviledge)
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: "Failed to update token for identity with more privileged role"
name: "PermissionBoundaryError",
message: "Failed to update token for identity with more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
const [token] = await identityAccessTokenDAL.update(
@@ -8,7 +8,7 @@ import { IdentityAuthMethod } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { validatePermissionBoundary } from "@app/lib/casl/boundary";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError, ForbiddenRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
import { checkIPAgainstBlocklist, extractIPDetails, isValidIpOrCidr, TIp } from "@app/lib/ip";
@@ -367,9 +367,12 @@ export const identityUaServiceFactory = ({
actorAuthMethod,
actorOrgId
);
if (!isAtLeastAsPrivileged(permission, rolePermission))
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: "Failed to revoke universal auth of identity with more privileged role"
name: "PermissionBoundaryError",
message: "Failed to revoke universal auth of identity with more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
const revokedIdentityUniversalAuth = await identityUaDAL.transaction(async (tx) => {
@@ -414,10 +417,12 @@ export const identityUaServiceFactory = ({
actorAuthMethod,
actorOrgId
);
const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasPriviledge)
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: "Failed to add identity to project with more privileged role"
name: "PermissionBoundaryError",
message: "Failed to create client secret for a more privileged identity.",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
const appCfg = getConfig();
@@ -475,9 +480,12 @@ export const identityUaServiceFactory = ({
actorOrgId
);
if (!isAtLeastAsPrivileged(permission, rolePermission))
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: "Failed to add identity to project with more privileged role"
name: "PermissionBoundaryError",
message: "Failed to get identity client secret with more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
const identityUniversalAuth = await identityUaDAL.findOne({
@@ -524,9 +532,12 @@ export const identityUaServiceFactory = ({
actorAuthMethod,
actorOrgId
);
if (!isAtLeastAsPrivileged(permission, rolePermission))
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: "Failed to read identity client secret of project with more privileged role"
name: "PermissionBoundaryError",
message: "Failed to read identity client secret of identity with more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
const clientSecret = await identityUaClientSecretDAL.findById(clientSecretId);
@@ -566,10 +577,12 @@ export const identityUaServiceFactory = ({
actorAuthMethod,
actorOrgId
);
if (!isAtLeastAsPrivileged(permission, rolePermission))
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: "Failed to revoke identity client secret with more privileged role"
name: "PermissionBoundaryError",
message: "Failed to revoke identity client secret with more privileged role",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
const clientSecret = await identityUaClientSecretDAL.updateById(clientSecretId, {
@@ -4,7 +4,7 @@ import { OrgMembershipRole, TableName, TOrgRoles } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { validatePermissionBoundary } from "@app/lib/casl/boundary";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { TIdentityProjectDALFactory } from "@app/services/identity-project/identity-project-dal";
@@ -58,9 +58,13 @@ export const identityServiceFactory = ({
orgId
);
const isCustomRole = Boolean(customRole);
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasRequiredPriviledges)
throw new ForbiddenRequestError({ message: "Failed to create a more privileged identity" });
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
name: "PermissionBoundaryError",
message: "Failed to create a more privileged identity",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
const plan = await licenseService.getPlan(orgId);
@@ -129,9 +133,13 @@ export const identityServiceFactory = ({
actorAuthMethod,
actorOrgId
);
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, identityRolePermission);
if (!hasRequiredPriviledges)
throw new ForbiddenRequestError({ message: "Failed to delete more privileged identity" });
const permissionBoundary = validatePermissionBoundary(permission, identityRolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
name: "PermissionBoundaryError",
message: "Failed to update a more privileged identity",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
let customRole: TOrgRoles | undefined;
if (role) {
@@ -141,9 +149,13 @@ export const identityServiceFactory = ({
);
const isCustomRole = Boolean(customOrgRole);
const hasRequiredNewRolePermission = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasRequiredNewRolePermission)
throw new ForbiddenRequestError({ message: "Failed to create a more privileged identity" });
const appliedRolePermissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!appliedRolePermissionBoundary.isValid)
throw new ForbiddenRequestError({
name: "PermissionBoundaryError",
message: "Failed to create a more privileged identity",
details: { missingPermissions: appliedRolePermissionBoundary.missingPermissions }
});
if (isCustomRole) customRole = customOrgRole;
}
@@ -216,9 +228,13 @@ export const identityServiceFactory = ({
actorAuthMethod,
actorOrgId
);
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, identityRolePermission);
if (!hasRequiredPriviledges)
throw new ForbiddenRequestError({ message: "Failed to delete more privileged identity" });
const permissionBoundary = validatePermissionBoundary(permission, identityRolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
name: "PermissionBoundaryError",
message: "Failed to delete more privileged identity",
details: { missingPermissions: permissionBoundary.missingPermissions }
});
const deletedIdentity = await identityDAL.deleteById(id);
@@ -7,7 +7,7 @@ import { TLicenseServiceFactory } from "@app/ee/services/license/license-service
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { TProjectUserAdditionalPrivilegeDALFactory } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-dal";
import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { validatePermissionBoundary } from "@app/lib/casl/boundary";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { groupBy } from "@app/lib/fn";
@@ -274,13 +274,13 @@ export const projectMembershipServiceFactory = ({
projectId
);
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasRequiredPriviledges) {
const permissionBoundary = validatePermissionBoundary(permission, rolePermission);
if (!permissionBoundary.isValid)
throw new ForbiddenRequestError({
message: `Failed to change to a more privileged role ${requestedRoleChange}`
name: "PermissionBoundaryError",
message: `Failed to change to a more privileged role ${requestedRoleChange}`,
details: { missingPermissions: permissionBoundary.missingPermissions }
});
}
}
// validate custom roles input