mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 22:27:48 +00:00
feat: updated backend permission request definition
This commit is contained in:
@@ -6,8 +6,9 @@ import { ProjectMembershipRole, ProjectMembershipsSchema, ProjectRolesSchema } f
|
|||||||
import { PROJECT_ROLE } from "@app/lib/api-docs";
|
import { PROJECT_ROLE } from "@app/lib/api-docs";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { ProjectPermissionSchema, SanitizedRoleSchema } from "@app/server/routes/sanitizedSchemas";
|
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
import { ProjectPermissionSchema } from "@app/ee/services/permission/project-permission";
|
||||||
|
import { SanitizedRoleSchema } from "@app/server/routes/sanitizedSchemas";
|
||||||
|
|
||||||
export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
|
|||||||
+6
-12
@@ -34,18 +34,12 @@ export type TIdentityProjectAdditionalPrivilegeServiceFactory = ReturnType<
|
|||||||
|
|
||||||
// TODO(akhilmhdh): move this to more centralized
|
// TODO(akhilmhdh): move this to more centralized
|
||||||
export const UnpackedPermissionSchema = z.object({
|
export const UnpackedPermissionSchema = z.object({
|
||||||
subject: z.union([z.string().min(1), z.string().array()]).optional(),
|
subject: z
|
||||||
action: z.union([z.string().min(1), z.string().array()]),
|
.union([z.string().min(1), z.string().array()])
|
||||||
conditions: z
|
.transform((el) => (typeof el !== "string" ? el[0] : el))
|
||||||
.object({
|
.optional(),
|
||||||
environment: z.string().optional(),
|
action: z.union([z.string().min(1), z.string().array()]).transform((el) => (typeof el === "string" ? [el] : el)),
|
||||||
secretPath: z
|
conditions: z.unknown().optional()
|
||||||
.object({
|
|
||||||
$glob: z.string().min(1)
|
|
||||||
})
|
|
||||||
.optional()
|
|
||||||
})
|
|
||||||
.optional()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const unpackPermissions = (permissions: unknown) =>
|
const unpackPermissions = (permissions: unknown) =>
|
||||||
|
|||||||
@@ -1,9 +1,46 @@
|
|||||||
|
import picomatch from "picomatch";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
export type TBuildProjectPermissionDTO = {
|
export type TBuildProjectPermissionDTO = {
|
||||||
permissions?: unknown;
|
permissions?: unknown;
|
||||||
role: string;
|
role: string;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
export type TBuildOrgPermissionDTO = {
|
export enum PermissionConditionOperators {
|
||||||
permissions?: unknown;
|
$IN = "$in",
|
||||||
role: string;
|
$ALL = "$all",
|
||||||
}[];
|
$REGEX = "$regex",
|
||||||
|
$EQ = "$eq",
|
||||||
|
$NEQ = "$neq",
|
||||||
|
$GLOB = "$glob"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PermissionConditionSchema = {
|
||||||
|
[PermissionConditionOperators.$IN]: z.string().array(),
|
||||||
|
[PermissionConditionOperators.$ALL]: z.string().array(),
|
||||||
|
[PermissionConditionOperators.$REGEX]: z.string().refine(
|
||||||
|
(el) => {
|
||||||
|
try {
|
||||||
|
// eslint-disable-next-line no-new
|
||||||
|
new RegExp(el);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ message: "Invalid regex pattern" }
|
||||||
|
),
|
||||||
|
[PermissionConditionOperators.$EQ]: z.string(),
|
||||||
|
[PermissionConditionOperators.$NEQ]: z.string(),
|
||||||
|
[PermissionConditionOperators.$GLOB]: z.string().refine(
|
||||||
|
(el) => {
|
||||||
|
try {
|
||||||
|
picomatch.parse([el]);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ message: "Invalid glob pattern" }
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { AbilityBuilder, createMongoAbility, ForcedSubject, MongoAbility } from "@casl/ability";
|
import { AbilityBuilder, createMongoAbility, ForcedSubject, MongoAbility } from "@casl/ability";
|
||||||
|
|
||||||
import { conditionsMatcher } from "@app/lib/casl";
|
import { conditionsMatcher } from "@app/lib/casl";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { z } from "zod";
|
||||||
|
import { PermissionConditionOperators, PermissionConditionSchema } from "./permission-types";
|
||||||
|
|
||||||
export enum ProjectPermissionActions {
|
export enum ProjectPermissionActions {
|
||||||
Read = "read",
|
Read = "read",
|
||||||
@@ -76,128 +77,296 @@ export type ProjectPermissionSet =
|
|||||||
| [ProjectPermissionActions.Create, ProjectPermissionSub.SecretRollback]
|
| [ProjectPermissionActions.Create, ProjectPermissionSub.SecretRollback]
|
||||||
| [ProjectPermissionActions.Edit, ProjectPermissionSub.Kms];
|
| [ProjectPermissionActions.Edit, ProjectPermissionSub.Kms];
|
||||||
|
|
||||||
export const fullProjectPermissionSet: [ProjectPermissionActions, ProjectPermissionSub][] = [
|
const CASL_ACTION_SCHEMA_NATIVE_ENUM = <ACTION extends z.EnumLike>(actions: ACTION) =>
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.Secrets],
|
z
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.Secrets],
|
.union([z.nativeEnum(actions), z.nativeEnum(actions).array().min(1)])
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.Secrets],
|
.transform((el) => (typeof el === "string" ? [el] : el));
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.Secrets],
|
|
||||||
|
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval],
|
const CASL_ACTION_SCHEMA_ENUM = <ACTION extends z.EnumValues>(actions: ACTION) =>
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.SecretApproval],
|
z.union([z.enum(actions), z.enum(actions).array().min(1)]).transform((el) => (typeof el === "string" ? [el] : el));
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.SecretApproval],
|
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.SecretApproval],
|
|
||||||
|
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation],
|
const SecretConditionSchema = z
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.SecretRotation],
|
.object({
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.SecretRotation],
|
environment: z.union([
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.SecretRotation],
|
z.string(),
|
||||||
|
z
|
||||||
|
.object({
|
||||||
|
[PermissionConditionOperators.$EQ]: PermissionConditionSchema[PermissionConditionOperators.$EQ],
|
||||||
|
[PermissionConditionOperators.$NEQ]: PermissionConditionSchema[PermissionConditionOperators.$NEQ],
|
||||||
|
[PermissionConditionOperators.$IN]: PermissionConditionSchema[PermissionConditionOperators.$IN],
|
||||||
|
[PermissionConditionOperators.$ALL]: PermissionConditionSchema[PermissionConditionOperators.$ALL],
|
||||||
|
[PermissionConditionOperators.$REGEX]: PermissionConditionSchema[PermissionConditionOperators.$REGEX],
|
||||||
|
[PermissionConditionOperators.$GLOB]: PermissionConditionSchema[PermissionConditionOperators.$GLOB]
|
||||||
|
})
|
||||||
|
.partial()
|
||||||
|
]),
|
||||||
|
secretPath: z.union([
|
||||||
|
z.string(),
|
||||||
|
z
|
||||||
|
.object({
|
||||||
|
[PermissionConditionOperators.$EQ]: PermissionConditionSchema[PermissionConditionOperators.$EQ],
|
||||||
|
[PermissionConditionOperators.$NEQ]: PermissionConditionSchema[PermissionConditionOperators.$NEQ],
|
||||||
|
[PermissionConditionOperators.$IN]: PermissionConditionSchema[PermissionConditionOperators.$IN],
|
||||||
|
[PermissionConditionOperators.$ALL]: PermissionConditionSchema[PermissionConditionOperators.$ALL],
|
||||||
|
[PermissionConditionOperators.$REGEX]: PermissionConditionSchema[PermissionConditionOperators.$REGEX],
|
||||||
|
[PermissionConditionOperators.$GLOB]: PermissionConditionSchema[PermissionConditionOperators.$GLOB]
|
||||||
|
})
|
||||||
|
.partial()
|
||||||
|
]),
|
||||||
|
secretName: z.union([
|
||||||
|
z.string(),
|
||||||
|
z
|
||||||
|
.object({
|
||||||
|
[PermissionConditionOperators.$EQ]: PermissionConditionSchema[PermissionConditionOperators.$EQ],
|
||||||
|
[PermissionConditionOperators.$NEQ]: PermissionConditionSchema[PermissionConditionOperators.$NEQ],
|
||||||
|
[PermissionConditionOperators.$IN]: PermissionConditionSchema[PermissionConditionOperators.$IN],
|
||||||
|
[PermissionConditionOperators.$ALL]: PermissionConditionSchema[PermissionConditionOperators.$ALL],
|
||||||
|
[PermissionConditionOperators.$REGEX]: PermissionConditionSchema[PermissionConditionOperators.$REGEX],
|
||||||
|
[PermissionConditionOperators.$GLOB]: PermissionConditionSchema[PermissionConditionOperators.$GLOB]
|
||||||
|
})
|
||||||
|
.partial()
|
||||||
|
])
|
||||||
|
})
|
||||||
|
.partial();
|
||||||
|
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback],
|
export const ProjectPermissionSchema = z.discriminatedUnion("subject", [
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.SecretRollback],
|
z.object({
|
||||||
|
subject: z
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.Member],
|
.literal(ProjectPermissionSub.Secrets)
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.Member],
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.Member],
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.Member],
|
"Describe what action an entity can take."
|
||||||
|
),
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.Groups],
|
conditions: SecretConditionSchema.describe(
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.Groups],
|
"When specified, only matching conditions will be allowed to access given resource."
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.Groups],
|
).optional()
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.Groups],
|
}),
|
||||||
|
z.object({
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.Role],
|
subject: z
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.Role],
|
.literal(ProjectPermissionSub.SecretApproval)
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.Role],
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.Role],
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.Integrations],
|
)
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.Integrations],
|
}),
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.Integrations],
|
z.object({
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations],
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.SecretRotation)
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.Webhooks],
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.Webhooks],
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.Webhooks],
|
"Describe what action an entity can take."
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.Webhooks],
|
)
|
||||||
|
}),
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.Identity],
|
z.object({
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.Identity],
|
subject: z
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.Identity],
|
.literal(ProjectPermissionSub.SecretRollback)
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.Identity],
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_ENUM([ProjectPermissionActions.Read, ProjectPermissionActions.Create]).describe(
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.ServiceTokens],
|
"Describe what action an entity can take."
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.ServiceTokens],
|
)
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.ServiceTokens],
|
}),
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.ServiceTokens],
|
z.object({
|
||||||
|
subject: z
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.Settings],
|
.literal(ProjectPermissionSub.Member)
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.Settings],
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.Settings],
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.Settings],
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.Environments],
|
}),
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.Environments],
|
z.object({
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.Environments],
|
subject: z
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.Environments],
|
.literal(ProjectPermissionSub.Groups)
|
||||||
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.Tags],
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.Tags],
|
"Describe what action an entity can take."
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.Tags],
|
)
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.Tags],
|
}),
|
||||||
|
z.object({
|
||||||
// TODO(Daniel): Remove the audit logs permissions from project-level permissions.
|
subject: z
|
||||||
// TODO: We haven't done this yet because it might break existing roles, since those roles will become "invalid" since the audit log permission defined on those roles, no longer exist in the project-level defined permissions.
|
.literal(ProjectPermissionSub.Role)
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs],
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.AuditLogs],
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.AuditLogs],
|
"Describe what action an entity can take."
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.AuditLogs],
|
)
|
||||||
|
}),
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.IpAllowList],
|
z.object({
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList],
|
subject: z
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.IpAllowList],
|
.literal(ProjectPermissionSub.Integrations)
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.IpAllowList],
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
// double check if all CRUD are needed for CA and Certificates
|
"Describe what action an entity can take."
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.CertificateAuthorities],
|
)
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.CertificateAuthorities],
|
}),
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.CertificateAuthorities],
|
z.object({
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.CertificateAuthorities],
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.Webhooks)
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.Certificates],
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.Certificates],
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.Certificates],
|
"Describe what action an entity can take."
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.Certificates],
|
)
|
||||||
|
}),
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.CertificateTemplates],
|
z.object({
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.CertificateTemplates],
|
subject: z
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.CertificateTemplates],
|
.literal(ProjectPermissionSub.Identity)
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.CertificateTemplates],
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.PkiAlerts],
|
"Describe what action an entity can take."
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.PkiAlerts],
|
)
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.PkiAlerts],
|
}),
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.PkiAlerts],
|
z.object({
|
||||||
|
subject: z
|
||||||
[ProjectPermissionActions.Read, ProjectPermissionSub.PkiCollections],
|
.literal(ProjectPermissionSub.ServiceTokens)
|
||||||
[ProjectPermissionActions.Create, ProjectPermissionSub.PkiCollections],
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.PkiCollections],
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.PkiCollections],
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.Project],
|
}),
|
||||||
[ProjectPermissionActions.Delete, ProjectPermissionSub.Project],
|
z.object({
|
||||||
|
subject: z
|
||||||
[ProjectPermissionActions.Edit, ProjectPermissionSub.Kms]
|
.literal(ProjectPermissionSub.Settings)
|
||||||
];
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.Environments)
|
||||||
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.Tags)
|
||||||
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.AuditLogs)
|
||||||
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.IpAllowList)
|
||||||
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.CertificateAuthorities)
|
||||||
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.Certificates)
|
||||||
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.CertificateTemplates)
|
||||||
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.PkiAlerts)
|
||||||
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.PkiCollections)
|
||||||
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.Project)
|
||||||
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_ENUM([ProjectPermissionActions.Edit, ProjectPermissionActions.Delete]).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.Kms)
|
||||||
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_ENUM([ProjectPermissionActions.Edit]).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z
|
||||||
|
.literal(ProjectPermissionSub.SecretFolders)
|
||||||
|
.describe("The entity this permission pertains to. Possible options: secrets, environments"),
|
||||||
|
action: CASL_ACTION_SCHEMA_ENUM([ProjectPermissionActions.Read]).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
const buildAdminPermissionRules = () => {
|
const buildAdminPermissionRules = () => {
|
||||||
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
||||||
|
|
||||||
// Admins get full access to everything
|
// Admins get full access to everything
|
||||||
fullProjectPermissionSet.forEach((permission) => {
|
[
|
||||||
const [action, subject] = permission;
|
ProjectPermissionSub.Secrets,
|
||||||
can(action, subject);
|
ProjectPermissionSub.SecretApproval,
|
||||||
|
ProjectPermissionSub.SecretRotation,
|
||||||
|
ProjectPermissionSub.Member,
|
||||||
|
ProjectPermissionSub.Groups,
|
||||||
|
ProjectPermissionSub.Role,
|
||||||
|
ProjectPermissionSub.Integrations,
|
||||||
|
ProjectPermissionSub.Webhooks,
|
||||||
|
ProjectPermissionSub.Identity,
|
||||||
|
ProjectPermissionSub.ServiceTokens,
|
||||||
|
ProjectPermissionSub.Settings,
|
||||||
|
ProjectPermissionSub.Environments,
|
||||||
|
ProjectPermissionSub.Tags,
|
||||||
|
ProjectPermissionSub.AuditLogs,
|
||||||
|
ProjectPermissionSub.IpAllowList,
|
||||||
|
ProjectPermissionSub.CertificateAuthorities,
|
||||||
|
ProjectPermissionSub.Certificates,
|
||||||
|
ProjectPermissionSub.CertificateTemplates,
|
||||||
|
ProjectPermissionSub.PkiAlerts,
|
||||||
|
ProjectPermissionSub.PkiCollections
|
||||||
|
].forEach((el) => {
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
el as ProjectPermissionSub
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
can([ProjectPermissionActions.Edit, ProjectPermissionActions.Delete], ProjectPermissionSub.Project);
|
||||||
|
can([ProjectPermissionActions.Read, ProjectPermissionActions.Create], ProjectPermissionSub.SecretRollback);
|
||||||
|
can([ProjectPermissionActions.Edit], ProjectPermissionSub.Kms);
|
||||||
return rules;
|
return rules;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -206,73 +375,116 @@ export const projectAdminPermissions = buildAdminPermissionRules();
|
|||||||
const buildMemberPermissionRules = () => {
|
const buildMemberPermissionRules = () => {
|
||||||
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Secrets);
|
can(
|
||||||
can(ProjectPermissionActions.Create, ProjectPermissionSub.Secrets);
|
[
|
||||||
can(ProjectPermissionActions.Edit, ProjectPermissionSub.Secrets);
|
ProjectPermissionActions.Read,
|
||||||
can(ProjectPermissionActions.Delete, ProjectPermissionSub.Secrets);
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Secrets
|
||||||
|
);
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval);
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.SecretApproval);
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation);
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.SecretRotation);
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
|
can([ProjectPermissionActions.Read, ProjectPermissionActions.Create], ProjectPermissionSub.SecretRollback);
|
||||||
can(ProjectPermissionActions.Create, ProjectPermissionSub.SecretRollback);
|
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Member);
|
can([ProjectPermissionActions.Read, ProjectPermissionActions.Create], ProjectPermissionSub.Member);
|
||||||
can(ProjectPermissionActions.Create, ProjectPermissionSub.Member);
|
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Groups);
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.Groups);
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
can(
|
||||||
can(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
|
[
|
||||||
can(ProjectPermissionActions.Edit, ProjectPermissionSub.Integrations);
|
ProjectPermissionActions.Read,
|
||||||
can(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations);
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Integrations
|
||||||
|
);
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Webhooks);
|
can(
|
||||||
can(ProjectPermissionActions.Create, ProjectPermissionSub.Webhooks);
|
[
|
||||||
can(ProjectPermissionActions.Edit, ProjectPermissionSub.Webhooks);
|
ProjectPermissionActions.Read,
|
||||||
can(ProjectPermissionActions.Delete, ProjectPermissionSub.Webhooks);
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Webhooks
|
||||||
|
);
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Identity);
|
can(
|
||||||
can(ProjectPermissionActions.Create, ProjectPermissionSub.Identity);
|
[
|
||||||
can(ProjectPermissionActions.Edit, ProjectPermissionSub.Identity);
|
ProjectPermissionActions.Read,
|
||||||
can(ProjectPermissionActions.Delete, ProjectPermissionSub.Identity);
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Identity
|
||||||
|
);
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.ServiceTokens);
|
can(
|
||||||
can(ProjectPermissionActions.Create, ProjectPermissionSub.ServiceTokens);
|
[
|
||||||
can(ProjectPermissionActions.Edit, ProjectPermissionSub.ServiceTokens);
|
ProjectPermissionActions.Read,
|
||||||
can(ProjectPermissionActions.Delete, ProjectPermissionSub.ServiceTokens);
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.ServiceTokens
|
||||||
|
);
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Settings);
|
can(
|
||||||
can(ProjectPermissionActions.Create, ProjectPermissionSub.Settings);
|
[
|
||||||
can(ProjectPermissionActions.Edit, ProjectPermissionSub.Settings);
|
ProjectPermissionActions.Read,
|
||||||
can(ProjectPermissionActions.Delete, ProjectPermissionSub.Settings);
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Settings
|
||||||
|
);
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Environments);
|
can(
|
||||||
can(ProjectPermissionActions.Create, ProjectPermissionSub.Environments);
|
[
|
||||||
can(ProjectPermissionActions.Edit, ProjectPermissionSub.Environments);
|
ProjectPermissionActions.Read,
|
||||||
can(ProjectPermissionActions.Delete, ProjectPermissionSub.Environments);
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Environments
|
||||||
|
);
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Tags);
|
can(
|
||||||
can(ProjectPermissionActions.Create, ProjectPermissionSub.Tags);
|
[
|
||||||
can(ProjectPermissionActions.Edit, ProjectPermissionSub.Tags);
|
ProjectPermissionActions.Read,
|
||||||
can(ProjectPermissionActions.Delete, ProjectPermissionSub.Tags);
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Tags
|
||||||
|
);
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Role);
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.Role);
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs);
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.AuditLogs);
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.IpAllowList);
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.IpAllowList);
|
||||||
|
|
||||||
// double check if all CRUD are needed for CA and Certificates
|
// double check if all CRUD are needed for CA and Certificates
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.CertificateAuthorities);
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.CertificateAuthorities);
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Certificates);
|
can(
|
||||||
can(ProjectPermissionActions.Create, ProjectPermissionSub.Certificates);
|
[
|
||||||
can(ProjectPermissionActions.Edit, ProjectPermissionSub.Certificates);
|
ProjectPermissionActions.Read,
|
||||||
can(ProjectPermissionActions.Delete, ProjectPermissionSub.Certificates);
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Certificates
|
||||||
|
);
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.CertificateTemplates);
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.CertificateTemplates);
|
||||||
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.PkiAlerts);
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.PkiAlerts);
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.PkiCollections);
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.PkiCollections);
|
||||||
|
|
||||||
return rules;
|
return rules;
|
||||||
};
|
};
|
||||||
@@ -382,32 +594,4 @@ export const isAtLeastAsPrivilegedWorkspace = (
|
|||||||
|
|
||||||
return set1.size >= set2.size;
|
return set1.size >= set2.size;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Case: The user requests to create a role with permissions that are not valid and not supposed to be used ever.
|
|
||||||
* If we don't check for this, we can run into issues where functions like the `isAtLeastAsPrivileged` will not work as expected, because we compare the size of each permission set.
|
|
||||||
* If the permission set contains invalid permissions, the size will be different, and result in incorrect results.
|
|
||||||
*/
|
|
||||||
export const validateProjectPermissions = (permissions: unknown) => {
|
|
||||||
const parsedPermissions =
|
|
||||||
typeof permissions === "string" ? (JSON.parse(permissions) as string[]) : (permissions as string[]);
|
|
||||||
|
|
||||||
const flattenedPermissions = [...parsedPermissions];
|
|
||||||
|
|
||||||
for (const perm of flattenedPermissions) {
|
|
||||||
const [action, subject] = perm;
|
|
||||||
|
|
||||||
if (
|
|
||||||
!fullProjectPermissionSet.find(
|
|
||||||
(currentPermission) => currentPermission[0] === action && currentPermission[1] === subject
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: `Permission action ${action} on subject ${subject} is not valid`,
|
|
||||||
name: "Create Role"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* eslint-enable */
|
/* eslint-enable */
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionSet,
|
ProjectPermissionSet,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub
|
||||||
validateProjectPermissions
|
|
||||||
} from "@app/ee/services/permission/project-permission";
|
} from "@app/ee/services/permission/project-permission";
|
||||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
|
|
||||||
@@ -60,8 +59,6 @@ export const projectRoleServiceFactory = ({
|
|||||||
throw new BadRequestError({ name: "Create Role", message: "Project role with same slug already exists" });
|
throw new BadRequestError({ name: "Create Role", message: "Project role with same slug already exists" });
|
||||||
}
|
}
|
||||||
|
|
||||||
validateProjectPermissions(data.permissions);
|
|
||||||
|
|
||||||
const role = await projectRoleDAL.create({
|
const role = await projectRoleDAL.create({
|
||||||
...data,
|
...data,
|
||||||
projectId
|
projectId
|
||||||
@@ -127,10 +124,6 @@ export const projectRoleServiceFactory = ({
|
|||||||
throw new BadRequestError({ name: "Update Role", message: "Project role with the same slug already exists" });
|
throw new BadRequestError({ name: "Update Role", message: "Project role with the same slug already exists" });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.permissions) {
|
|
||||||
validateProjectPermissions(data.permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
const [updatedRole] = await projectRoleDAL.update(
|
const [updatedRole] = await projectRoleDAL.update(
|
||||||
{ id: roleId, projectId },
|
{ id: roleId, projectId },
|
||||||
{
|
{
|
||||||
|
|||||||
+2
-2
@@ -217,7 +217,7 @@ export const formRolePermission2API = (formVal: TFormSchema["permissions"]) => {
|
|||||||
Object.entries(formVal || {}).forEach(([subject, rules]) => {
|
Object.entries(formVal || {}).forEach(([subject, rules]) => {
|
||||||
rules.forEach((actions) => {
|
rules.forEach((actions) => {
|
||||||
const caslActions = Object.keys(actions).filter(
|
const caslActions = Object.keys(actions).filter(
|
||||||
(el) => actions?.[el as keyof typeof actions]
|
(el) => actions?.[el as keyof typeof actions] && el !== "conditions"
|
||||||
);
|
);
|
||||||
const caslConditions =
|
const caslConditions =
|
||||||
"conditions" in actions
|
"conditions" in actions
|
||||||
@@ -226,7 +226,7 @@ export const formRolePermission2API = (formVal: TFormSchema["permissions"]) => {
|
|||||||
|
|
||||||
permissions.push({
|
permissions.push({
|
||||||
action: caslActions,
|
action: caslActions,
|
||||||
subject: [subject],
|
subject,
|
||||||
conditions: caslConditions
|
conditions: caslConditions
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user