Merge pull request #3550 from Infisical/project-specific-default-roles
Improvements: Refactor Project Templates and Project Type Policy Filtering/Specific Roles
@@ -0,0 +1,22 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { ProjectType, TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasColumn(TableName.ProjectTemplates, "type"))) {
|
||||||
|
await knex.schema.alterTable(TableName.ProjectTemplates, (t) => {
|
||||||
|
// defaulting to sm for migration to set existing, new ones will always be specified on creation
|
||||||
|
t.string("type").defaultTo(ProjectType.SecretManager).notNullable();
|
||||||
|
t.jsonb("environments").nullable().alter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
if (await knex.schema.hasColumn(TableName.ProjectTemplates, "type")) {
|
||||||
|
await knex.schema.alterTable(TableName.ProjectTemplates, (t) => {
|
||||||
|
t.dropColumn("type");
|
||||||
|
// not reverting nullable environments
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -185,11 +185,16 @@ export enum OrgMembershipStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum ProjectMembershipRole {
|
export enum ProjectMembershipRole {
|
||||||
|
// general
|
||||||
Admin = "admin",
|
Admin = "admin",
|
||||||
Member = "member",
|
Member = "member",
|
||||||
Custom = "custom",
|
Custom = "custom",
|
||||||
Viewer = "viewer",
|
Viewer = "viewer",
|
||||||
NoAccess = "no-access"
|
NoAccess = "no-access",
|
||||||
|
// ssh
|
||||||
|
SshHostBootstrapper = "ssh-host-bootstrapper",
|
||||||
|
// kms
|
||||||
|
KmsCryptographicOperator = "cryptographic-operator"
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum SecretEncryptionAlgo {
|
export enum SecretEncryptionAlgo {
|
||||||
|
|||||||
@@ -12,10 +12,11 @@ export const ProjectTemplatesSchema = z.object({
|
|||||||
name: z.string(),
|
name: z.string(),
|
||||||
description: z.string().nullable().optional(),
|
description: z.string().nullable().optional(),
|
||||||
roles: z.unknown(),
|
roles: z.unknown(),
|
||||||
environments: z.unknown(),
|
environments: z.unknown().nullable().optional(),
|
||||||
orgId: z.string().uuid(),
|
orgId: z.string().uuid(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date()
|
updatedAt: z.date(),
|
||||||
|
type: z.string().default("secret-manager")
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TProjectTemplates = z.infer<typeof ProjectTemplatesSchema>;
|
export type TProjectTemplates = z.infer<typeof ProjectTemplatesSchema>;
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { ProjectMembershipRole, ProjectTemplatesSchema } from "@app/db/schemas";
|
import { ProjectMembershipRole, ProjectTemplatesSchema, ProjectType } from "@app/db/schemas";
|
||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
import { ProjectTemplateDefaultEnvironments } from "@app/ee/services/project-template/project-template-constants";
|
|
||||||
import { isInfisicalProjectTemplate } from "@app/ee/services/project-template/project-template-fns";
|
import { isInfisicalProjectTemplate } from "@app/ee/services/project-template/project-template-fns";
|
||||||
import { ApiDocsTags, ProjectTemplates } from "@app/lib/api-docs";
|
import { ApiDocsTags, ProjectTemplates } from "@app/lib/api-docs";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
@@ -35,6 +34,7 @@ const SanitizedProjectTemplateSchema = ProjectTemplatesSchema.extend({
|
|||||||
position: z.number().min(1)
|
position: z.number().min(1)
|
||||||
})
|
})
|
||||||
.array()
|
.array()
|
||||||
|
.nullable()
|
||||||
});
|
});
|
||||||
|
|
||||||
const ProjectTemplateRolesSchema = z
|
const ProjectTemplateRolesSchema = z
|
||||||
@@ -104,6 +104,9 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
|
|||||||
hide: false,
|
hide: false,
|
||||||
tags: [ApiDocsTags.ProjectTemplates],
|
tags: [ApiDocsTags.ProjectTemplates],
|
||||||
description: "List project templates for the current organization.",
|
description: "List project templates for the current organization.",
|
||||||
|
querystring: z.object({
|
||||||
|
type: z.nativeEnum(ProjectType).optional().describe(ProjectTemplates.LIST.type)
|
||||||
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
projectTemplates: SanitizedProjectTemplateSchema.array()
|
projectTemplates: SanitizedProjectTemplateSchema.array()
|
||||||
@@ -112,7 +115,8 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const projectTemplates = await server.services.projectTemplate.listProjectTemplatesByOrg(req.permission);
|
const { type } = req.query;
|
||||||
|
const projectTemplates = await server.services.projectTemplate.listProjectTemplatesByOrg(req.permission, type);
|
||||||
|
|
||||||
const auditTemplates = projectTemplates.filter((template) => !isInfisicalProjectTemplate(template.name));
|
const auditTemplates = projectTemplates.filter((template) => !isInfisicalProjectTemplate(template.name));
|
||||||
|
|
||||||
@@ -184,6 +188,7 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
|
|||||||
tags: [ApiDocsTags.ProjectTemplates],
|
tags: [ApiDocsTags.ProjectTemplates],
|
||||||
description: "Create a project template.",
|
description: "Create a project template.",
|
||||||
body: z.object({
|
body: z.object({
|
||||||
|
type: z.nativeEnum(ProjectType).describe(ProjectTemplates.CREATE.type),
|
||||||
name: slugSchema({ field: "name" })
|
name: slugSchema({ field: "name" })
|
||||||
.refine((val) => !isInfisicalProjectTemplate(val), {
|
.refine((val) => !isInfisicalProjectTemplate(val), {
|
||||||
message: `The requested project template name is reserved.`
|
message: `The requested project template name is reserved.`
|
||||||
@@ -191,9 +196,7 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider)
|
|||||||
.describe(ProjectTemplates.CREATE.name),
|
.describe(ProjectTemplates.CREATE.name),
|
||||||
description: z.string().max(256).trim().optional().describe(ProjectTemplates.CREATE.description),
|
description: z.string().max(256).trim().optional().describe(ProjectTemplates.CREATE.description),
|
||||||
roles: ProjectTemplateRolesSchema.default([]).describe(ProjectTemplates.CREATE.roles),
|
roles: ProjectTemplateRolesSchema.default([]).describe(ProjectTemplates.CREATE.roles),
|
||||||
environments: ProjectTemplateEnvironmentsSchema.default(ProjectTemplateDefaultEnvironments).describe(
|
environments: ProjectTemplateEnvironmentsSchema.describe(ProjectTemplates.CREATE.environments).optional()
|
||||||
ProjectTemplates.CREATE.environments
|
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
|
|||||||
@@ -0,0 +1,448 @@
|
|||||||
|
import { AbilityBuilder, createMongoAbility, MongoAbility } from "@casl/ability";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ProjectPermissionActions,
|
||||||
|
ProjectPermissionCertificateActions,
|
||||||
|
ProjectPermissionCmekActions,
|
||||||
|
ProjectPermissionDynamicSecretActions,
|
||||||
|
ProjectPermissionGroupActions,
|
||||||
|
ProjectPermissionIdentityActions,
|
||||||
|
ProjectPermissionKmipActions,
|
||||||
|
ProjectPermissionMemberActions,
|
||||||
|
ProjectPermissionSecretActions,
|
||||||
|
ProjectPermissionSecretRotationActions,
|
||||||
|
ProjectPermissionSecretSyncActions,
|
||||||
|
ProjectPermissionSet,
|
||||||
|
ProjectPermissionSshHostActions,
|
||||||
|
ProjectPermissionSub
|
||||||
|
} from "@app/ee/services/permission/project-permission";
|
||||||
|
|
||||||
|
const buildAdminPermissionRules = () => {
|
||||||
|
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
||||||
|
|
||||||
|
// Admins get full access to everything
|
||||||
|
[
|
||||||
|
ProjectPermissionSub.SecretFolders,
|
||||||
|
ProjectPermissionSub.SecretImports,
|
||||||
|
ProjectPermissionSub.SecretApproval,
|
||||||
|
ProjectPermissionSub.Role,
|
||||||
|
ProjectPermissionSub.Integrations,
|
||||||
|
ProjectPermissionSub.Webhooks,
|
||||||
|
ProjectPermissionSub.ServiceTokens,
|
||||||
|
ProjectPermissionSub.Settings,
|
||||||
|
ProjectPermissionSub.Environments,
|
||||||
|
ProjectPermissionSub.Tags,
|
||||||
|
ProjectPermissionSub.AuditLogs,
|
||||||
|
ProjectPermissionSub.IpAllowList,
|
||||||
|
ProjectPermissionSub.CertificateAuthorities,
|
||||||
|
ProjectPermissionSub.CertificateTemplates,
|
||||||
|
ProjectPermissionSub.PkiAlerts,
|
||||||
|
ProjectPermissionSub.PkiCollections,
|
||||||
|
ProjectPermissionSub.SshCertificateAuthorities,
|
||||||
|
ProjectPermissionSub.SshCertificates,
|
||||||
|
ProjectPermissionSub.SshCertificateTemplates,
|
||||||
|
ProjectPermissionSub.SshHostGroups
|
||||||
|
].forEach((el) => {
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
el
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionCertificateActions.Read,
|
||||||
|
ProjectPermissionCertificateActions.Edit,
|
||||||
|
ProjectPermissionCertificateActions.Create,
|
||||||
|
ProjectPermissionCertificateActions.Delete,
|
||||||
|
ProjectPermissionCertificateActions.ReadPrivateKey
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Certificates
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionSshHostActions.Edit,
|
||||||
|
ProjectPermissionSshHostActions.Read,
|
||||||
|
ProjectPermissionSshHostActions.Create,
|
||||||
|
ProjectPermissionSshHostActions.Delete,
|
||||||
|
ProjectPermissionSshHostActions.IssueHostCert
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.SshHosts
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionMemberActions.Create,
|
||||||
|
ProjectPermissionMemberActions.Edit,
|
||||||
|
ProjectPermissionMemberActions.Delete,
|
||||||
|
ProjectPermissionMemberActions.Read,
|
||||||
|
ProjectPermissionMemberActions.GrantPrivileges,
|
||||||
|
ProjectPermissionMemberActions.AssumePrivileges
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Member
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionGroupActions.Create,
|
||||||
|
ProjectPermissionGroupActions.Edit,
|
||||||
|
ProjectPermissionGroupActions.Delete,
|
||||||
|
ProjectPermissionGroupActions.Read,
|
||||||
|
ProjectPermissionGroupActions.GrantPrivileges
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Groups
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionIdentityActions.Create,
|
||||||
|
ProjectPermissionIdentityActions.Edit,
|
||||||
|
ProjectPermissionIdentityActions.Delete,
|
||||||
|
ProjectPermissionIdentityActions.Read,
|
||||||
|
ProjectPermissionIdentityActions.GrantPrivileges,
|
||||||
|
ProjectPermissionIdentityActions.AssumePrivileges
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Identity
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionSecretActions.DescribeAndReadValue,
|
||||||
|
ProjectPermissionSecretActions.DescribeSecret,
|
||||||
|
ProjectPermissionSecretActions.ReadValue,
|
||||||
|
ProjectPermissionSecretActions.Create,
|
||||||
|
ProjectPermissionSecretActions.Edit,
|
||||||
|
ProjectPermissionSecretActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Secrets
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionDynamicSecretActions.ReadRootCredential,
|
||||||
|
ProjectPermissionDynamicSecretActions.EditRootCredential,
|
||||||
|
ProjectPermissionDynamicSecretActions.CreateRootCredential,
|
||||||
|
ProjectPermissionDynamicSecretActions.DeleteRootCredential,
|
||||||
|
ProjectPermissionDynamicSecretActions.Lease
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.DynamicSecrets
|
||||||
|
);
|
||||||
|
|
||||||
|
can([ProjectPermissionActions.Edit, ProjectPermissionActions.Delete], ProjectPermissionSub.Project);
|
||||||
|
can([ProjectPermissionActions.Read, ProjectPermissionActions.Create], ProjectPermissionSub.SecretRollback);
|
||||||
|
can([ProjectPermissionActions.Edit], ProjectPermissionSub.Kms);
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionCmekActions.Create,
|
||||||
|
ProjectPermissionCmekActions.Edit,
|
||||||
|
ProjectPermissionCmekActions.Delete,
|
||||||
|
ProjectPermissionCmekActions.Read,
|
||||||
|
ProjectPermissionCmekActions.Encrypt,
|
||||||
|
ProjectPermissionCmekActions.Decrypt,
|
||||||
|
ProjectPermissionCmekActions.Sign,
|
||||||
|
ProjectPermissionCmekActions.Verify
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Cmek
|
||||||
|
);
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionSecretSyncActions.Create,
|
||||||
|
ProjectPermissionSecretSyncActions.Edit,
|
||||||
|
ProjectPermissionSecretSyncActions.Delete,
|
||||||
|
ProjectPermissionSecretSyncActions.Read,
|
||||||
|
ProjectPermissionSecretSyncActions.SyncSecrets,
|
||||||
|
ProjectPermissionSecretSyncActions.ImportSecrets,
|
||||||
|
ProjectPermissionSecretSyncActions.RemoveSecrets
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.SecretSyncs
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionKmipActions.CreateClients,
|
||||||
|
ProjectPermissionKmipActions.UpdateClients,
|
||||||
|
ProjectPermissionKmipActions.DeleteClients,
|
||||||
|
ProjectPermissionKmipActions.ReadClients,
|
||||||
|
ProjectPermissionKmipActions.GenerateClientCertificates
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Kmip
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionSecretRotationActions.Create,
|
||||||
|
ProjectPermissionSecretRotationActions.Edit,
|
||||||
|
ProjectPermissionSecretRotationActions.Delete,
|
||||||
|
ProjectPermissionSecretRotationActions.Read,
|
||||||
|
ProjectPermissionSecretRotationActions.ReadGeneratedCredentials,
|
||||||
|
ProjectPermissionSecretRotationActions.RotateSecrets
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.SecretRotation
|
||||||
|
);
|
||||||
|
|
||||||
|
return rules;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildMemberPermissionRules = () => {
|
||||||
|
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionSecretActions.DescribeAndReadValue,
|
||||||
|
ProjectPermissionSecretActions.DescribeSecret,
|
||||||
|
ProjectPermissionSecretActions.ReadValue,
|
||||||
|
ProjectPermissionSecretActions.Edit,
|
||||||
|
ProjectPermissionSecretActions.Create,
|
||||||
|
ProjectPermissionSecretActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Secrets
|
||||||
|
);
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.SecretFolders
|
||||||
|
);
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionDynamicSecretActions.ReadRootCredential,
|
||||||
|
ProjectPermissionDynamicSecretActions.EditRootCredential,
|
||||||
|
ProjectPermissionDynamicSecretActions.CreateRootCredential,
|
||||||
|
ProjectPermissionDynamicSecretActions.DeleteRootCredential,
|
||||||
|
ProjectPermissionDynamicSecretActions.Lease
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.DynamicSecrets
|
||||||
|
);
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.SecretImports
|
||||||
|
);
|
||||||
|
|
||||||
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.SecretApproval);
|
||||||
|
can([ProjectPermissionSecretRotationActions.Read], ProjectPermissionSub.SecretRotation);
|
||||||
|
|
||||||
|
can([ProjectPermissionActions.Read, ProjectPermissionActions.Create], ProjectPermissionSub.SecretRollback);
|
||||||
|
|
||||||
|
can([ProjectPermissionMemberActions.Read, ProjectPermissionMemberActions.Create], ProjectPermissionSub.Member);
|
||||||
|
|
||||||
|
can([ProjectPermissionGroupActions.Read], ProjectPermissionSub.Groups);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Integrations
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Webhooks
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionIdentityActions.Read,
|
||||||
|
ProjectPermissionIdentityActions.Edit,
|
||||||
|
ProjectPermissionIdentityActions.Create,
|
||||||
|
ProjectPermissionIdentityActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Identity
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.ServiceTokens
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Settings
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Environments
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionActions.Read,
|
||||||
|
ProjectPermissionActions.Edit,
|
||||||
|
ProjectPermissionActions.Create,
|
||||||
|
ProjectPermissionActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Tags
|
||||||
|
);
|
||||||
|
|
||||||
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.Role);
|
||||||
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.AuditLogs);
|
||||||
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.IpAllowList);
|
||||||
|
|
||||||
|
// double check if all CRUD are needed for CA and Certificates
|
||||||
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.CertificateAuthorities);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionCertificateActions.Read,
|
||||||
|
ProjectPermissionCertificateActions.Edit,
|
||||||
|
ProjectPermissionCertificateActions.Create,
|
||||||
|
ProjectPermissionCertificateActions.Delete
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Certificates
|
||||||
|
);
|
||||||
|
|
||||||
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.CertificateTemplates);
|
||||||
|
|
||||||
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.PkiAlerts);
|
||||||
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.PkiCollections);
|
||||||
|
|
||||||
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificates);
|
||||||
|
can([ProjectPermissionActions.Create], ProjectPermissionSub.SshCertificates);
|
||||||
|
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificateTemplates);
|
||||||
|
|
||||||
|
can([ProjectPermissionSshHostActions.Read], ProjectPermissionSub.SshHosts);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionCmekActions.Create,
|
||||||
|
ProjectPermissionCmekActions.Edit,
|
||||||
|
ProjectPermissionCmekActions.Delete,
|
||||||
|
ProjectPermissionCmekActions.Read,
|
||||||
|
ProjectPermissionCmekActions.Encrypt,
|
||||||
|
ProjectPermissionCmekActions.Decrypt,
|
||||||
|
ProjectPermissionCmekActions.Sign,
|
||||||
|
ProjectPermissionCmekActions.Verify
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Cmek
|
||||||
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionSecretSyncActions.Create,
|
||||||
|
ProjectPermissionSecretSyncActions.Edit,
|
||||||
|
ProjectPermissionSecretSyncActions.Delete,
|
||||||
|
ProjectPermissionSecretSyncActions.Read,
|
||||||
|
ProjectPermissionSecretSyncActions.SyncSecrets,
|
||||||
|
ProjectPermissionSecretSyncActions.ImportSecrets,
|
||||||
|
ProjectPermissionSecretSyncActions.RemoveSecrets
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.SecretSyncs
|
||||||
|
);
|
||||||
|
|
||||||
|
return rules;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildViewerPermissionRules = () => {
|
||||||
|
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
||||||
|
|
||||||
|
can(ProjectPermissionSecretActions.DescribeAndReadValue, ProjectPermissionSub.Secrets);
|
||||||
|
can(ProjectPermissionSecretActions.DescribeSecret, ProjectPermissionSub.Secrets);
|
||||||
|
can(ProjectPermissionSecretActions.ReadValue, ProjectPermissionSub.Secrets);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretFolders);
|
||||||
|
can(ProjectPermissionDynamicSecretActions.ReadRootCredential, ProjectPermissionSub.DynamicSecrets);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretImports);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
|
||||||
|
can(ProjectPermissionSecretRotationActions.Read, ProjectPermissionSub.SecretRotation);
|
||||||
|
can(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member);
|
||||||
|
can(ProjectPermissionGroupActions.Read, ProjectPermissionSub.Groups);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.Role);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.Webhooks);
|
||||||
|
can(ProjectPermissionIdentityActions.Read, ProjectPermissionSub.Identity);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.ServiceTokens);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.Settings);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.Environments);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.Tags);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.IpAllowList);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.CertificateAuthorities);
|
||||||
|
can(ProjectPermissionCertificateActions.Read, ProjectPermissionSub.Certificates);
|
||||||
|
can(ProjectPermissionCmekActions.Read, ProjectPermissionSub.Cmek);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.SshCertificates);
|
||||||
|
can(ProjectPermissionActions.Read, ProjectPermissionSub.SshCertificateTemplates);
|
||||||
|
can(ProjectPermissionSecretSyncActions.Read, ProjectPermissionSub.SecretSyncs);
|
||||||
|
|
||||||
|
return rules;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildNoAccessProjectPermission = () => {
|
||||||
|
const { rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
||||||
|
return rules;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildSshHostBootstrapPermissionRules = () => {
|
||||||
|
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[ProjectPermissionSshHostActions.Create, ProjectPermissionSshHostActions.IssueHostCert],
|
||||||
|
ProjectPermissionSub.SshHosts
|
||||||
|
);
|
||||||
|
|
||||||
|
return rules;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildCryptographicOperatorPermissionRules = () => {
|
||||||
|
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[
|
||||||
|
ProjectPermissionCmekActions.Encrypt,
|
||||||
|
ProjectPermissionCmekActions.Decrypt,
|
||||||
|
ProjectPermissionCmekActions.Sign,
|
||||||
|
ProjectPermissionCmekActions.Verify
|
||||||
|
],
|
||||||
|
ProjectPermissionSub.Cmek
|
||||||
|
);
|
||||||
|
|
||||||
|
return rules;
|
||||||
|
};
|
||||||
|
|
||||||
|
// General
|
||||||
|
export const projectAdminPermissions = buildAdminPermissionRules();
|
||||||
|
export const projectMemberPermissions = buildMemberPermissionRules();
|
||||||
|
export const projectViewerPermission = buildViewerPermissionRules();
|
||||||
|
export const projectNoAccessPermissions = buildNoAccessProjectPermission();
|
||||||
|
|
||||||
|
// SSH
|
||||||
|
export const sshHostBootstrapPermissions = buildSshHostBootstrapPermissionRules();
|
||||||
|
|
||||||
|
// KMS
|
||||||
|
export const cryptographicOperatorPermissions = buildCryptographicOperatorPermissionRules();
|
||||||
@@ -12,6 +12,14 @@ import {
|
|||||||
TIdentityProjectMemberships,
|
TIdentityProjectMemberships,
|
||||||
TProjectMemberships
|
TProjectMemberships
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
|
import {
|
||||||
|
cryptographicOperatorPermissions,
|
||||||
|
projectAdminPermissions,
|
||||||
|
projectMemberPermissions,
|
||||||
|
projectNoAccessPermissions,
|
||||||
|
projectViewerPermission,
|
||||||
|
sshHostBootstrapPermissions
|
||||||
|
} from "@app/ee/services/permission/default-roles";
|
||||||
import { conditionsMatcher } from "@app/lib/casl";
|
import { conditionsMatcher } from "@app/lib/casl";
|
||||||
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { objectify } from "@app/lib/fn";
|
import { objectify } from "@app/lib/fn";
|
||||||
@@ -32,14 +40,7 @@ import {
|
|||||||
TGetServiceTokenProjectPermissionArg,
|
TGetServiceTokenProjectPermissionArg,
|
||||||
TGetUserProjectPermissionArg
|
TGetUserProjectPermissionArg
|
||||||
} from "./permission-service-types";
|
} from "./permission-service-types";
|
||||||
import {
|
import { buildServiceTokenProjectPermission, ProjectPermissionSet } from "./project-permission";
|
||||||
buildServiceTokenProjectPermission,
|
|
||||||
projectAdminPermissions,
|
|
||||||
projectMemberPermissions,
|
|
||||||
projectNoAccessPermissions,
|
|
||||||
ProjectPermissionSet,
|
|
||||||
projectViewerPermission
|
|
||||||
} from "./project-permission";
|
|
||||||
|
|
||||||
type TPermissionServiceFactoryDep = {
|
type TPermissionServiceFactoryDep = {
|
||||||
orgRoleDAL: Pick<TOrgRoleDALFactory, "findOne">;
|
orgRoleDAL: Pick<TOrgRoleDALFactory, "findOne">;
|
||||||
@@ -95,6 +96,10 @@ export const permissionServiceFactory = ({
|
|||||||
return projectViewerPermission;
|
return projectViewerPermission;
|
||||||
case ProjectMembershipRole.NoAccess:
|
case ProjectMembershipRole.NoAccess:
|
||||||
return projectNoAccessPermissions;
|
return projectNoAccessPermissions;
|
||||||
|
case ProjectMembershipRole.SshHostBootstrapper:
|
||||||
|
return sshHostBootstrapPermissions;
|
||||||
|
case ProjectMembershipRole.KmsCryptographicOperator:
|
||||||
|
return cryptographicOperatorPermissions;
|
||||||
case ProjectMembershipRole.Custom: {
|
case ProjectMembershipRole.Custom: {
|
||||||
return unpackRules<RawRuleOf<MongoAbility<ProjectPermissionSet>>>(
|
return unpackRules<RawRuleOf<MongoAbility<ProjectPermissionSet>>>(
|
||||||
permissions as PackRule<RawRuleOf<MongoAbility<ProjectPermissionSet>>>[]
|
permissions as PackRule<RawRuleOf<MongoAbility<ProjectPermissionSet>>>[]
|
||||||
|
|||||||
@@ -678,403 +678,6 @@ export const ProjectPermissionV2Schema = z.discriminatedUnion("subject", [
|
|||||||
|
|
||||||
export type TProjectPermissionV2Schema = z.infer<typeof ProjectPermissionV2Schema>;
|
export type TProjectPermissionV2Schema = z.infer<typeof ProjectPermissionV2Schema>;
|
||||||
|
|
||||||
const buildAdminPermissionRules = () => {
|
|
||||||
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
|
||||||
|
|
||||||
// Admins get full access to everything
|
|
||||||
[
|
|
||||||
ProjectPermissionSub.SecretFolders,
|
|
||||||
ProjectPermissionSub.SecretImports,
|
|
||||||
ProjectPermissionSub.SecretApproval,
|
|
||||||
ProjectPermissionSub.Role,
|
|
||||||
ProjectPermissionSub.Integrations,
|
|
||||||
ProjectPermissionSub.Webhooks,
|
|
||||||
ProjectPermissionSub.ServiceTokens,
|
|
||||||
ProjectPermissionSub.Settings,
|
|
||||||
ProjectPermissionSub.Environments,
|
|
||||||
ProjectPermissionSub.Tags,
|
|
||||||
ProjectPermissionSub.AuditLogs,
|
|
||||||
ProjectPermissionSub.IpAllowList,
|
|
||||||
ProjectPermissionSub.CertificateAuthorities,
|
|
||||||
ProjectPermissionSub.CertificateTemplates,
|
|
||||||
ProjectPermissionSub.PkiAlerts,
|
|
||||||
ProjectPermissionSub.PkiCollections,
|
|
||||||
ProjectPermissionSub.SshCertificateAuthorities,
|
|
||||||
ProjectPermissionSub.SshCertificates,
|
|
||||||
ProjectPermissionSub.SshCertificateTemplates,
|
|
||||||
ProjectPermissionSub.SshHostGroups
|
|
||||||
].forEach((el) => {
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionActions.Edit,
|
|
||||||
ProjectPermissionActions.Create,
|
|
||||||
ProjectPermissionActions.Delete
|
|
||||||
],
|
|
||||||
el
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionCertificateActions.Read,
|
|
||||||
ProjectPermissionCertificateActions.Edit,
|
|
||||||
ProjectPermissionCertificateActions.Create,
|
|
||||||
ProjectPermissionCertificateActions.Delete,
|
|
||||||
ProjectPermissionCertificateActions.ReadPrivateKey
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Certificates
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionSshHostActions.Edit,
|
|
||||||
ProjectPermissionSshHostActions.Read,
|
|
||||||
ProjectPermissionSshHostActions.Create,
|
|
||||||
ProjectPermissionSshHostActions.Delete,
|
|
||||||
ProjectPermissionSshHostActions.IssueHostCert
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.SshHosts
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionMemberActions.Create,
|
|
||||||
ProjectPermissionMemberActions.Edit,
|
|
||||||
ProjectPermissionMemberActions.Delete,
|
|
||||||
ProjectPermissionMemberActions.Read,
|
|
||||||
ProjectPermissionMemberActions.GrantPrivileges,
|
|
||||||
ProjectPermissionMemberActions.AssumePrivileges
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Member
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionGroupActions.Create,
|
|
||||||
ProjectPermissionGroupActions.Edit,
|
|
||||||
ProjectPermissionGroupActions.Delete,
|
|
||||||
ProjectPermissionGroupActions.Read,
|
|
||||||
ProjectPermissionGroupActions.GrantPrivileges
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Groups
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionIdentityActions.Create,
|
|
||||||
ProjectPermissionIdentityActions.Edit,
|
|
||||||
ProjectPermissionIdentityActions.Delete,
|
|
||||||
ProjectPermissionIdentityActions.Read,
|
|
||||||
ProjectPermissionIdentityActions.GrantPrivileges,
|
|
||||||
ProjectPermissionIdentityActions.AssumePrivileges
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Identity
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionSecretActions.DescribeAndReadValue,
|
|
||||||
ProjectPermissionSecretActions.DescribeSecret,
|
|
||||||
ProjectPermissionSecretActions.ReadValue,
|
|
||||||
ProjectPermissionSecretActions.Create,
|
|
||||||
ProjectPermissionSecretActions.Edit,
|
|
||||||
ProjectPermissionSecretActions.Delete
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Secrets
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionDynamicSecretActions.ReadRootCredential,
|
|
||||||
ProjectPermissionDynamicSecretActions.EditRootCredential,
|
|
||||||
ProjectPermissionDynamicSecretActions.CreateRootCredential,
|
|
||||||
ProjectPermissionDynamicSecretActions.DeleteRootCredential,
|
|
||||||
ProjectPermissionDynamicSecretActions.Lease
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.DynamicSecrets
|
|
||||||
);
|
|
||||||
|
|
||||||
can([ProjectPermissionActions.Edit, ProjectPermissionActions.Delete], ProjectPermissionSub.Project);
|
|
||||||
can([ProjectPermissionActions.Read, ProjectPermissionActions.Create], ProjectPermissionSub.SecretRollback);
|
|
||||||
can([ProjectPermissionActions.Edit], ProjectPermissionSub.Kms);
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionCmekActions.Create,
|
|
||||||
ProjectPermissionCmekActions.Edit,
|
|
||||||
ProjectPermissionCmekActions.Delete,
|
|
||||||
ProjectPermissionCmekActions.Read,
|
|
||||||
ProjectPermissionCmekActions.Encrypt,
|
|
||||||
ProjectPermissionCmekActions.Decrypt,
|
|
||||||
ProjectPermissionCmekActions.Sign,
|
|
||||||
ProjectPermissionCmekActions.Verify
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Cmek
|
|
||||||
);
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionSecretSyncActions.Create,
|
|
||||||
ProjectPermissionSecretSyncActions.Edit,
|
|
||||||
ProjectPermissionSecretSyncActions.Delete,
|
|
||||||
ProjectPermissionSecretSyncActions.Read,
|
|
||||||
ProjectPermissionSecretSyncActions.SyncSecrets,
|
|
||||||
ProjectPermissionSecretSyncActions.ImportSecrets,
|
|
||||||
ProjectPermissionSecretSyncActions.RemoveSecrets
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.SecretSyncs
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionKmipActions.CreateClients,
|
|
||||||
ProjectPermissionKmipActions.UpdateClients,
|
|
||||||
ProjectPermissionKmipActions.DeleteClients,
|
|
||||||
ProjectPermissionKmipActions.ReadClients,
|
|
||||||
ProjectPermissionKmipActions.GenerateClientCertificates
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Kmip
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionSecretRotationActions.Create,
|
|
||||||
ProjectPermissionSecretRotationActions.Edit,
|
|
||||||
ProjectPermissionSecretRotationActions.Delete,
|
|
||||||
ProjectPermissionSecretRotationActions.Read,
|
|
||||||
ProjectPermissionSecretRotationActions.ReadGeneratedCredentials,
|
|
||||||
ProjectPermissionSecretRotationActions.RotateSecrets
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.SecretRotation
|
|
||||||
);
|
|
||||||
|
|
||||||
return rules;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const projectAdminPermissions = buildAdminPermissionRules();
|
|
||||||
|
|
||||||
const buildMemberPermissionRules = () => {
|
|
||||||
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionSecretActions.DescribeAndReadValue,
|
|
||||||
ProjectPermissionSecretActions.DescribeSecret,
|
|
||||||
ProjectPermissionSecretActions.ReadValue,
|
|
||||||
ProjectPermissionSecretActions.Edit,
|
|
||||||
ProjectPermissionSecretActions.Create,
|
|
||||||
ProjectPermissionSecretActions.Delete
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Secrets
|
|
||||||
);
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionActions.Edit,
|
|
||||||
ProjectPermissionActions.Create,
|
|
||||||
ProjectPermissionActions.Delete
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.SecretFolders
|
|
||||||
);
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionDynamicSecretActions.ReadRootCredential,
|
|
||||||
ProjectPermissionDynamicSecretActions.EditRootCredential,
|
|
||||||
ProjectPermissionDynamicSecretActions.CreateRootCredential,
|
|
||||||
ProjectPermissionDynamicSecretActions.DeleteRootCredential,
|
|
||||||
ProjectPermissionDynamicSecretActions.Lease
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.DynamicSecrets
|
|
||||||
);
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionActions.Edit,
|
|
||||||
ProjectPermissionActions.Create,
|
|
||||||
ProjectPermissionActions.Delete
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.SecretImports
|
|
||||||
);
|
|
||||||
|
|
||||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.SecretApproval);
|
|
||||||
can([ProjectPermissionSecretRotationActions.Read], ProjectPermissionSub.SecretRotation);
|
|
||||||
|
|
||||||
can([ProjectPermissionActions.Read, ProjectPermissionActions.Create], ProjectPermissionSub.SecretRollback);
|
|
||||||
|
|
||||||
can([ProjectPermissionMemberActions.Read, ProjectPermissionMemberActions.Create], ProjectPermissionSub.Member);
|
|
||||||
|
|
||||||
can([ProjectPermissionGroupActions.Read], ProjectPermissionSub.Groups);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionActions.Edit,
|
|
||||||
ProjectPermissionActions.Create,
|
|
||||||
ProjectPermissionActions.Delete
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Integrations
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionActions.Edit,
|
|
||||||
ProjectPermissionActions.Create,
|
|
||||||
ProjectPermissionActions.Delete
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Webhooks
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionIdentityActions.Read,
|
|
||||||
ProjectPermissionIdentityActions.Edit,
|
|
||||||
ProjectPermissionIdentityActions.Create,
|
|
||||||
ProjectPermissionIdentityActions.Delete
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Identity
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionActions.Edit,
|
|
||||||
ProjectPermissionActions.Create,
|
|
||||||
ProjectPermissionActions.Delete
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.ServiceTokens
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionActions.Edit,
|
|
||||||
ProjectPermissionActions.Create,
|
|
||||||
ProjectPermissionActions.Delete
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Settings
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionActions.Edit,
|
|
||||||
ProjectPermissionActions.Create,
|
|
||||||
ProjectPermissionActions.Delete
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Environments
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionActions.Read,
|
|
||||||
ProjectPermissionActions.Edit,
|
|
||||||
ProjectPermissionActions.Create,
|
|
||||||
ProjectPermissionActions.Delete
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Tags
|
|
||||||
);
|
|
||||||
|
|
||||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.Role);
|
|
||||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.AuditLogs);
|
|
||||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.IpAllowList);
|
|
||||||
|
|
||||||
// double check if all CRUD are needed for CA and Certificates
|
|
||||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.CertificateAuthorities);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionCertificateActions.Read,
|
|
||||||
ProjectPermissionCertificateActions.Edit,
|
|
||||||
ProjectPermissionCertificateActions.Create,
|
|
||||||
ProjectPermissionCertificateActions.Delete
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Certificates
|
|
||||||
);
|
|
||||||
|
|
||||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.CertificateTemplates);
|
|
||||||
|
|
||||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.PkiAlerts);
|
|
||||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.PkiCollections);
|
|
||||||
|
|
||||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificates);
|
|
||||||
can([ProjectPermissionActions.Create], ProjectPermissionSub.SshCertificates);
|
|
||||||
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificateTemplates);
|
|
||||||
|
|
||||||
can([ProjectPermissionSshHostActions.Read], ProjectPermissionSub.SshHosts);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionCmekActions.Create,
|
|
||||||
ProjectPermissionCmekActions.Edit,
|
|
||||||
ProjectPermissionCmekActions.Delete,
|
|
||||||
ProjectPermissionCmekActions.Read,
|
|
||||||
ProjectPermissionCmekActions.Encrypt,
|
|
||||||
ProjectPermissionCmekActions.Decrypt,
|
|
||||||
ProjectPermissionCmekActions.Sign,
|
|
||||||
ProjectPermissionCmekActions.Verify
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.Cmek
|
|
||||||
);
|
|
||||||
|
|
||||||
can(
|
|
||||||
[
|
|
||||||
ProjectPermissionSecretSyncActions.Create,
|
|
||||||
ProjectPermissionSecretSyncActions.Edit,
|
|
||||||
ProjectPermissionSecretSyncActions.Delete,
|
|
||||||
ProjectPermissionSecretSyncActions.Read,
|
|
||||||
ProjectPermissionSecretSyncActions.SyncSecrets,
|
|
||||||
ProjectPermissionSecretSyncActions.ImportSecrets,
|
|
||||||
ProjectPermissionSecretSyncActions.RemoveSecrets
|
|
||||||
],
|
|
||||||
ProjectPermissionSub.SecretSyncs
|
|
||||||
);
|
|
||||||
|
|
||||||
return rules;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const projectMemberPermissions = buildMemberPermissionRules();
|
|
||||||
|
|
||||||
const buildViewerPermissionRules = () => {
|
|
||||||
const { can, rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
|
||||||
|
|
||||||
can(ProjectPermissionSecretActions.DescribeAndReadValue, ProjectPermissionSub.Secrets);
|
|
||||||
can(ProjectPermissionSecretActions.DescribeSecret, ProjectPermissionSub.Secrets);
|
|
||||||
can(ProjectPermissionSecretActions.ReadValue, ProjectPermissionSub.Secrets);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretFolders);
|
|
||||||
can(ProjectPermissionDynamicSecretActions.ReadRootCredential, ProjectPermissionSub.DynamicSecrets);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretImports);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
|
|
||||||
can(ProjectPermissionSecretRotationActions.Read, ProjectPermissionSub.SecretRotation);
|
|
||||||
can(ProjectPermissionMemberActions.Read, ProjectPermissionSub.Member);
|
|
||||||
can(ProjectPermissionGroupActions.Read, ProjectPermissionSub.Groups);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Role);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Webhooks);
|
|
||||||
can(ProjectPermissionIdentityActions.Read, ProjectPermissionSub.Identity);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.ServiceTokens);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Settings);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Environments);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.Tags);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.IpAllowList);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.CertificateAuthorities);
|
|
||||||
can(ProjectPermissionCertificateActions.Read, ProjectPermissionSub.Certificates);
|
|
||||||
can(ProjectPermissionCmekActions.Read, ProjectPermissionSub.Cmek);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.SshCertificates);
|
|
||||||
can(ProjectPermissionActions.Read, ProjectPermissionSub.SshCertificateTemplates);
|
|
||||||
can(ProjectPermissionSecretSyncActions.Read, ProjectPermissionSub.SecretSyncs);
|
|
||||||
|
|
||||||
return rules;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const projectViewerPermission = buildViewerPermissionRules();
|
|
||||||
|
|
||||||
const buildNoAccessProjectPermission = () => {
|
|
||||||
const { rules } = new AbilityBuilder<MongoAbility<ProjectPermissionSet>>(createMongoAbility);
|
|
||||||
return rules;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const buildServiceTokenProjectPermission = (
|
export const buildServiceTokenProjectPermission = (
|
||||||
scopes: Array<{ secretPath: string; environment: string }>,
|
scopes: Array<{ secretPath: string; environment: string }>,
|
||||||
permission: string[]
|
permission: string[]
|
||||||
@@ -1116,8 +719,6 @@ export const buildServiceTokenProjectPermission = (
|
|||||||
return build({ conditionsMatcher });
|
return build({ conditionsMatcher });
|
||||||
};
|
};
|
||||||
|
|
||||||
export const projectNoAccessPermissions = buildNoAccessProjectPermission();
|
|
||||||
|
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,22 +1,27 @@
|
|||||||
import { ProjectTemplateDefaultEnvironments } from "@app/ee/services/project-template/project-template-constants";
|
import { ProjectType } from "@app/db/schemas";
|
||||||
import {
|
import {
|
||||||
InfisicalProjectTemplate,
|
InfisicalProjectTemplate,
|
||||||
TUnpackedPermission
|
TUnpackedPermission
|
||||||
} from "@app/ee/services/project-template/project-template-types";
|
} from "@app/ee/services/project-template/project-template-types";
|
||||||
import { getPredefinedRoles } from "@app/services/project-role/project-role-fns";
|
import { getPredefinedRoles } from "@app/services/project-role/project-role-fns";
|
||||||
|
|
||||||
export const getDefaultProjectTemplate = (orgId: string) => ({
|
import { ProjectTemplateDefaultEnvironments } from "./project-template-constants";
|
||||||
|
|
||||||
|
export const getDefaultProjectTemplate = (orgId: string, type: ProjectType) => ({
|
||||||
id: "b11b49a9-09a9-4443-916a-4246f9ff2c69", // random ID to appease zod
|
id: "b11b49a9-09a9-4443-916a-4246f9ff2c69", // random ID to appease zod
|
||||||
|
type,
|
||||||
name: InfisicalProjectTemplate.Default,
|
name: InfisicalProjectTemplate.Default,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
description: "Infisical's default project template",
|
description: `Infisical's ${type} default project template`,
|
||||||
environments: ProjectTemplateDefaultEnvironments,
|
environments: type === ProjectType.SecretManager ? ProjectTemplateDefaultEnvironments : null,
|
||||||
roles: [...getPredefinedRoles("project-template")].map(({ name, slug, permissions }) => ({
|
roles: [...getPredefinedRoles({ projectId: "project-template", projectType: type })].map(
|
||||||
name,
|
({ name, slug, permissions }) => ({
|
||||||
slug,
|
name,
|
||||||
permissions: permissions as TUnpackedPermission[]
|
slug,
|
||||||
})),
|
permissions: permissions as TUnpackedPermission[]
|
||||||
|
})
|
||||||
|
),
|
||||||
orgId
|
orgId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import { packRules } from "@casl/ability/extra";
|
import { packRules } from "@casl/ability/extra";
|
||||||
|
|
||||||
import { TProjectTemplates } from "@app/db/schemas";
|
import { ProjectType, TProjectTemplates } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
|
import { ProjectTemplateDefaultEnvironments } from "@app/ee/services/project-template/project-template-constants";
|
||||||
import { getDefaultProjectTemplate } from "@app/ee/services/project-template/project-template-fns";
|
import { getDefaultProjectTemplate } from "@app/ee/services/project-template/project-template-fns";
|
||||||
import {
|
import {
|
||||||
TCreateProjectTemplateDTO,
|
TCreateProjectTemplateDTO,
|
||||||
@@ -32,11 +33,13 @@ const $unpackProjectTemplate = ({ roles, environments, ...rest }: TProjectTempla
|
|||||||
...rest,
|
...rest,
|
||||||
environments: environments as TProjectTemplateEnvironment[],
|
environments: environments as TProjectTemplateEnvironment[],
|
||||||
roles: [
|
roles: [
|
||||||
...getPredefinedRoles("project-template").map(({ name, slug, permissions }) => ({
|
...getPredefinedRoles({ projectId: "project-template", projectType: rest.type as ProjectType }).map(
|
||||||
name,
|
({ name, slug, permissions }) => ({
|
||||||
slug,
|
name,
|
||||||
permissions: permissions as TUnpackedPermission[]
|
slug,
|
||||||
})),
|
permissions: permissions as TUnpackedPermission[]
|
||||||
|
})
|
||||||
|
),
|
||||||
...(roles as TProjectTemplateRole[]).map((role) => ({
|
...(roles as TProjectTemplateRole[]).map((role) => ({
|
||||||
...role,
|
...role,
|
||||||
permissions: unpackPermissions(role.permissions)
|
permissions: unpackPermissions(role.permissions)
|
||||||
@@ -49,7 +52,7 @@ export const projectTemplateServiceFactory = ({
|
|||||||
permissionService,
|
permissionService,
|
||||||
projectTemplateDAL
|
projectTemplateDAL
|
||||||
}: TProjectTemplatesServiceFactoryDep) => {
|
}: TProjectTemplatesServiceFactoryDep) => {
|
||||||
const listProjectTemplatesByOrg = async (actor: OrgServiceActor) => {
|
const listProjectTemplatesByOrg = async (actor: OrgServiceActor, type?: ProjectType) => {
|
||||||
const plan = await licenseService.getPlan(actor.orgId);
|
const plan = await licenseService.getPlan(actor.orgId);
|
||||||
|
|
||||||
if (!plan.projectTemplates)
|
if (!plan.projectTemplates)
|
||||||
@@ -68,11 +71,14 @@ export const projectTemplateServiceFactory = ({
|
|||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.ProjectTemplates);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.ProjectTemplates);
|
||||||
|
|
||||||
const projectTemplates = await projectTemplateDAL.find({
|
const projectTemplates = await projectTemplateDAL.find({
|
||||||
orgId: actor.orgId
|
orgId: actor.orgId,
|
||||||
|
...(type ? { type } : {})
|
||||||
});
|
});
|
||||||
|
|
||||||
return [
|
return [
|
||||||
getDefaultProjectTemplate(actor.orgId),
|
...(type
|
||||||
|
? [getDefaultProjectTemplate(actor.orgId, type)]
|
||||||
|
: Object.values(ProjectType).map((projectType) => getDefaultProjectTemplate(actor.orgId, projectType))),
|
||||||
...projectTemplates.map((template) => $unpackProjectTemplate(template))
|
...projectTemplates.map((template) => $unpackProjectTemplate(template))
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
@@ -134,7 +140,7 @@ export const projectTemplateServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const createProjectTemplate = async (
|
const createProjectTemplate = async (
|
||||||
{ roles, environments, ...params }: TCreateProjectTemplateDTO,
|
{ roles, environments, type, ...params }: TCreateProjectTemplateDTO,
|
||||||
actor: OrgServiceActor
|
actor: OrgServiceActor
|
||||||
) => {
|
) => {
|
||||||
const plan = await licenseService.getPlan(actor.orgId);
|
const plan = await licenseService.getPlan(actor.orgId);
|
||||||
@@ -154,6 +160,17 @@ export const projectTemplateServiceFactory = ({
|
|||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.ProjectTemplates);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.ProjectTemplates);
|
||||||
|
|
||||||
|
if (environments && type !== ProjectType.SecretManager) {
|
||||||
|
throw new BadRequestError({ message: "Cannot configure environments for non-SecretManager project templates" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (environments && plan.environmentLimit !== null && environments.length > plan.environmentLimit) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||||
|
message: `Failed to create project template due to environment count exceeding your current limit of ${plan.environmentLimit}. Contact Infisical to increase limit.`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const isConflictingName = Boolean(
|
const isConflictingName = Boolean(
|
||||||
await projectTemplateDAL.findOne({
|
await projectTemplateDAL.findOne({
|
||||||
name: params.name,
|
name: params.name,
|
||||||
@@ -169,8 +186,10 @@ export const projectTemplateServiceFactory = ({
|
|||||||
const projectTemplate = await projectTemplateDAL.create({
|
const projectTemplate = await projectTemplateDAL.create({
|
||||||
...params,
|
...params,
|
||||||
roles: JSON.stringify(roles.map((role) => ({ ...role, permissions: packRules(role.permissions) }))),
|
roles: JSON.stringify(roles.map((role) => ({ ...role, permissions: packRules(role.permissions) }))),
|
||||||
environments: JSON.stringify(environments),
|
environments:
|
||||||
orgId: actor.orgId
|
type === ProjectType.SecretManager ? JSON.stringify(environments ?? ProjectTemplateDefaultEnvironments) : null,
|
||||||
|
orgId: actor.orgId,
|
||||||
|
type
|
||||||
});
|
});
|
||||||
|
|
||||||
return $unpackProjectTemplate(projectTemplate);
|
return $unpackProjectTemplate(projectTemplate);
|
||||||
@@ -202,6 +221,19 @@ export const projectTemplateServiceFactory = ({
|
|||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.ProjectTemplates);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.ProjectTemplates);
|
||||||
|
|
||||||
|
if (projectTemplate.type !== ProjectType.SecretManager && environments)
|
||||||
|
throw new BadRequestError({ message: "Cannot configure environments for non-SecretManager project templates" });
|
||||||
|
|
||||||
|
if (projectTemplate.type === ProjectType.SecretManager && environments === null)
|
||||||
|
throw new BadRequestError({ message: "Environments cannot be removed for SecretManager project templates" });
|
||||||
|
|
||||||
|
if (environments && plan.environmentLimit !== null && environments.length > plan.environmentLimit) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||||
|
message: `Failed to update project template due to environment count exceeding your current limit of ${plan.environmentLimit}. Contact Infisical to increase limit.`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (params.name && projectTemplate.name !== params.name) {
|
if (params.name && projectTemplate.name !== params.name) {
|
||||||
const isConflictingName = Boolean(
|
const isConflictingName = Boolean(
|
||||||
await projectTemplateDAL.findOne({
|
await projectTemplateDAL.findOne({
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { TProjectEnvironments } from "@app/db/schemas";
|
import { ProjectType, TProjectEnvironments } from "@app/db/schemas";
|
||||||
import { TProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
import { TProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
import { UnpackedPermissionSchema } from "@app/server/routes/sanitizedSchema/permission";
|
import { UnpackedPermissionSchema } from "@app/server/routes/sanitizedSchema/permission";
|
||||||
|
|
||||||
@@ -15,8 +15,9 @@ export type TProjectTemplateRole = {
|
|||||||
export type TCreateProjectTemplateDTO = {
|
export type TCreateProjectTemplateDTO = {
|
||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
type: ProjectType;
|
||||||
roles: TProjectTemplateRole[];
|
roles: TProjectTemplateRole[];
|
||||||
environments: TProjectTemplateEnvironment[];
|
environments?: TProjectTemplateEnvironment[] | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TUpdateProjectTemplateDTO = Partial<TCreateProjectTemplateDTO>;
|
export type TUpdateProjectTemplateDTO = Partial<TCreateProjectTemplateDTO>;
|
||||||
|
|||||||
@@ -1822,8 +1822,12 @@ export const KMS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const ProjectTemplates = {
|
export const ProjectTemplates = {
|
||||||
|
LIST: {
|
||||||
|
type: "The type of project template to list."
|
||||||
|
},
|
||||||
CREATE: {
|
CREATE: {
|
||||||
name: "The name of the project template to be created. Must be slug-friendly.",
|
name: "The name of the project template to be created. Must be slug-friendly.",
|
||||||
|
type: "The type of project template to be created.",
|
||||||
description: "An optional description of the project template.",
|
description: "An optional description of the project template.",
|
||||||
roles: "The roles to be created when the template is applied to a project.",
|
roles: "The roles to be created when the template is applied to a project.",
|
||||||
environments: "The environments to be created when the template is applied to a project."
|
environments: "The environments to be created when the template is applied to a project."
|
||||||
|
|||||||
@@ -1,15 +1,20 @@
|
|||||||
import { ProjectMembershipRole } from "@app/db/schemas";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
||||||
|
import { ProjectMembershipRole, ProjectType } from "@app/db/schemas";
|
||||||
import {
|
import {
|
||||||
|
cryptographicOperatorPermissions,
|
||||||
projectAdminPermissions,
|
projectAdminPermissions,
|
||||||
projectMemberPermissions,
|
projectMemberPermissions,
|
||||||
projectNoAccessPermissions,
|
projectNoAccessPermissions,
|
||||||
projectViewerPermission
|
projectViewerPermission,
|
||||||
} from "@app/ee/services/permission/project-permission";
|
sshHostBootstrapPermissions
|
||||||
|
} from "@app/ee/services/permission/default-roles";
|
||||||
|
import { TGetPredefinedRolesDTO } from "@app/services/project-role/project-role-types";
|
||||||
|
|
||||||
export const getPredefinedRoles = (projectId: string, roleFilter?: ProjectMembershipRole) => {
|
export const getPredefinedRoles = ({ projectId, projectType, roleFilter }: TGetPredefinedRolesDTO) => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: "b11b49a9-09a9-4443-916a-4246f9ff2c69", // dummy userid
|
id: uuidv4(),
|
||||||
projectId,
|
projectId,
|
||||||
name: "Admin",
|
name: "Admin",
|
||||||
slug: ProjectMembershipRole.Admin,
|
slug: ProjectMembershipRole.Admin,
|
||||||
@@ -19,7 +24,7 @@ export const getPredefinedRoles = (projectId: string, roleFilter?: ProjectMember
|
|||||||
updatedAt: new Date()
|
updatedAt: new Date()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "b11b49a9-09a9-4443-916a-4246f9ff2c70", // dummy user for zod validation in response
|
id: uuidv4(),
|
||||||
projectId,
|
projectId,
|
||||||
name: "Developer",
|
name: "Developer",
|
||||||
slug: ProjectMembershipRole.Member,
|
slug: ProjectMembershipRole.Member,
|
||||||
@@ -29,7 +34,29 @@ export const getPredefinedRoles = (projectId: string, roleFilter?: ProjectMember
|
|||||||
updatedAt: new Date()
|
updatedAt: new Date()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "b11b49a9-09a9-4443-916a-4246f9ff2c71", // dummy user for zod validation in response
|
id: uuidv4(),
|
||||||
|
projectId,
|
||||||
|
name: "SSH Host Bootstrapper",
|
||||||
|
slug: ProjectMembershipRole.SshHostBootstrapper,
|
||||||
|
permissions: sshHostBootstrapPermissions,
|
||||||
|
description: "Create and issue SSH Hosts in a project",
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
type: ProjectType.SSH
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: uuidv4(),
|
||||||
|
projectId,
|
||||||
|
name: "Cryptographic Operator",
|
||||||
|
slug: ProjectMembershipRole.KmsCryptographicOperator,
|
||||||
|
permissions: cryptographicOperatorPermissions,
|
||||||
|
description: "Perform cryptographic operations, such as encryption and signing, in a project",
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
type: ProjectType.KMS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: uuidv4(),
|
||||||
projectId,
|
projectId,
|
||||||
name: "Viewer",
|
name: "Viewer",
|
||||||
slug: ProjectMembershipRole.Viewer,
|
slug: ProjectMembershipRole.Viewer,
|
||||||
@@ -39,7 +66,7 @@ export const getPredefinedRoles = (projectId: string, roleFilter?: ProjectMember
|
|||||||
updatedAt: new Date()
|
updatedAt: new Date()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "b11b49a9-09a9-4443-916a-4246f9ff2c72", // dummy user for zod validation in response
|
id: uuidv4(),
|
||||||
projectId,
|
projectId,
|
||||||
name: "No Access",
|
name: "No Access",
|
||||||
slug: ProjectMembershipRole.NoAccess,
|
slug: ProjectMembershipRole.NoAccess,
|
||||||
@@ -48,5 +75,5 @@ export const getPredefinedRoles = (projectId: string, roleFilter?: ProjectMember
|
|||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
updatedAt: new Date()
|
updatedAt: new Date()
|
||||||
}
|
}
|
||||||
].filter(({ slug }) => !roleFilter || roleFilter.includes(slug));
|
].filter(({ slug, type }) => (type ? type === projectType : true) && (!roleFilter || roleFilter === slug));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { ForbiddenError, MongoAbility, RawRuleOf } from "@casl/ability";
|
|||||||
import { PackRule, packRules, unpackRules } from "@casl/ability/extra";
|
import { PackRule, packRules, unpackRules } from "@casl/ability/extra";
|
||||||
import { requestContext } from "@fastify/request-context";
|
import { requestContext } from "@fastify/request-context";
|
||||||
|
|
||||||
import { ActionProjectType, ProjectMembershipRole, TableName } from "@app/db/schemas";
|
import { ActionProjectType, ProjectMembershipRole, ProjectType, TableName, TProjects } from "@app/db/schemas";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
@@ -34,7 +34,7 @@ type TProjectRoleServiceFactoryDep = {
|
|||||||
projectRoleDAL: TProjectRoleDALFactory;
|
projectRoleDAL: TProjectRoleDALFactory;
|
||||||
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
userDAL: Pick<TUserDALFactory, "findById">;
|
userDAL: Pick<TUserDALFactory, "findById">;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
|
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug" | "findProjectById">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getUserProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getUserProjectPermission">;
|
||||||
identityProjectMembershipRoleDAL: TIdentityProjectMembershipRoleDALFactory;
|
identityProjectMembershipRoleDAL: TIdentityProjectMembershipRoleDALFactory;
|
||||||
projectUserMembershipRoleDAL: TProjectUserMembershipRoleDALFactory;
|
projectUserMembershipRoleDAL: TProjectUserMembershipRoleDALFactory;
|
||||||
@@ -98,30 +98,37 @@ export const projectRoleServiceFactory = ({
|
|||||||
roleSlug,
|
roleSlug,
|
||||||
filter
|
filter
|
||||||
}: TGetRoleDetailsDTO) => {
|
}: TGetRoleDetailsDTO) => {
|
||||||
let projectId = "";
|
let project: TProjects;
|
||||||
if (filter.type === ProjectRoleServiceIdentifierType.SLUG) {
|
if (filter.type === ProjectRoleServiceIdentifierType.SLUG) {
|
||||||
const project = await projectDAL.findProjectBySlug(filter.projectSlug, actorOrgId);
|
project = await projectDAL.findProjectBySlug(filter.projectSlug, actorOrgId);
|
||||||
if (!project) throw new NotFoundError({ message: "Project not found" });
|
|
||||||
projectId = project.id;
|
|
||||||
} else {
|
} else {
|
||||||
projectId = filter.projectId;
|
project = await projectDAL.findProjectById(filter.projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!project) throw new NotFoundError({ message: "Project not found" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
projectId,
|
projectId: project.id,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actionProjectType: ActionProjectType.Any
|
actionProjectType: ActionProjectType.Any
|
||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Role);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Role);
|
||||||
if (roleSlug !== "custom" && Object.values(ProjectMembershipRole).includes(roleSlug as ProjectMembershipRole)) {
|
if (roleSlug !== "custom" && Object.values(ProjectMembershipRole).includes(roleSlug as ProjectMembershipRole)) {
|
||||||
const predefinedRole = getPredefinedRoles(projectId, roleSlug as ProjectMembershipRole)[0];
|
const [predefinedRole] = getPredefinedRoles({
|
||||||
|
projectId: project.id,
|
||||||
|
projectType: project.type as ProjectType,
|
||||||
|
roleFilter: roleSlug as ProjectMembershipRole
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!predefinedRole) throw new NotFoundError({ message: `Default role with slug '${roleSlug}' not found` });
|
||||||
|
|
||||||
return { ...predefinedRole, permissions: UnpackedPermissionSchema.array().parse(predefinedRole.permissions) };
|
return { ...predefinedRole, permissions: UnpackedPermissionSchema.array().parse(predefinedRole.permissions) };
|
||||||
}
|
}
|
||||||
|
|
||||||
const customRole = await projectRoleDAL.findOne({ slug: roleSlug, projectId });
|
const customRole = await projectRoleDAL.findOne({ slug: roleSlug, projectId: project.id });
|
||||||
if (!customRole) throw new NotFoundError({ message: `Project role with slug '${roleSlug}' not found` });
|
if (!customRole) throw new NotFoundError({ message: `Project role with slug '${roleSlug}' not found` });
|
||||||
return { ...customRole, permissions: unpackPermissions(customRole.permissions) };
|
return { ...customRole, permissions: unpackPermissions(customRole.permissions) };
|
||||||
};
|
};
|
||||||
@@ -194,29 +201,32 @@ export const projectRoleServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const listRoles = async ({ actorOrgId, actorAuthMethod, actorId, actor, filter }: TListRolesDTO) => {
|
const listRoles = async ({ actorOrgId, actorAuthMethod, actorId, actor, filter }: TListRolesDTO) => {
|
||||||
let projectId = "";
|
let project: TProjects;
|
||||||
if (filter.type === ProjectRoleServiceIdentifierType.SLUG) {
|
if (filter.type === ProjectRoleServiceIdentifierType.SLUG) {
|
||||||
const project = await projectDAL.findProjectBySlug(filter.projectSlug, actorOrgId);
|
project = await projectDAL.findProjectBySlug(filter.projectSlug, actorOrgId);
|
||||||
if (!project) throw new BadRequestError({ message: "Project not found" });
|
|
||||||
projectId = project.id;
|
|
||||||
} else {
|
} else {
|
||||||
projectId = filter.projectId;
|
project = await projectDAL.findProjectById(filter.projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!project) throw new BadRequestError({ message: "Project not found" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
projectId,
|
projectId: project.id,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actionProjectType: ActionProjectType.Any
|
actionProjectType: ActionProjectType.Any
|
||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Role);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Role);
|
||||||
const customRoles = await projectRoleDAL.find(
|
const customRoles = await projectRoleDAL.find(
|
||||||
{ projectId },
|
{ projectId: project.id },
|
||||||
{ sort: [[`${TableName.ProjectRoles}.slug` as "slug", "asc"]] }
|
{ sort: [[`${TableName.ProjectRoles}.slug` as "slug", "asc"]] }
|
||||||
);
|
);
|
||||||
const roles = [...getPredefinedRoles(projectId), ...(customRoles || [])];
|
const roles = [
|
||||||
|
...getPredefinedRoles({ projectId: project.id, projectType: project.type as ProjectType }),
|
||||||
|
...(customRoles || [])
|
||||||
|
];
|
||||||
|
|
||||||
return roles;
|
return roles;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { TOrgRolesUpdate, TProjectRolesInsert } from "@app/db/schemas";
|
import { ProjectMembershipRole, ProjectType, TOrgRolesUpdate, TProjectRolesInsert } from "@app/db/schemas";
|
||||||
import { TProjectPermission } from "@app/lib/types";
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
|
|
||||||
export enum ProjectRoleServiceIdentifierType {
|
export enum ProjectRoleServiceIdentifierType {
|
||||||
@@ -34,3 +34,9 @@ export type TListRolesDTO = {
|
|||||||
| { type: ProjectRoleServiceIdentifierType.SLUG; projectSlug: string }
|
| { type: ProjectRoleServiceIdentifierType.SLUG; projectSlug: string }
|
||||||
| { type: ProjectRoleServiceIdentifierType.ID; projectId: string };
|
| { type: ProjectRoleServiceIdentifierType.ID; projectId: string };
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
|
export type TGetPredefinedRolesDTO = {
|
||||||
|
projectId: string;
|
||||||
|
projectType: ProjectType;
|
||||||
|
roleFilter?: ProjectMembershipRole;
|
||||||
|
};
|
||||||
|
|||||||
@@ -329,14 +329,16 @@ export const projectServiceFactory = ({
|
|||||||
// set default environments and root folder for provided environments
|
// set default environments and root folder for provided environments
|
||||||
let envs: TProjectEnvironments[] = [];
|
let envs: TProjectEnvironments[] = [];
|
||||||
if (projectTemplate) {
|
if (projectTemplate) {
|
||||||
envs = await projectEnvDAL.insertMany(
|
if (projectTemplate.environments) {
|
||||||
projectTemplate.environments.map((env) => ({ ...env, projectId: project.id })),
|
envs = await projectEnvDAL.insertMany(
|
||||||
tx
|
projectTemplate.environments.map((env) => ({ ...env, projectId: project.id })),
|
||||||
);
|
tx
|
||||||
await folderDAL.insertMany(
|
);
|
||||||
envs.map(({ id }) => ({ name: ROOT_FOLDER_NAME, envId: id, version: 1 })),
|
await folderDAL.insertMany(
|
||||||
tx
|
envs.map(({ id }) => ({ name: ROOT_FOLDER_NAME, envId: id, version: 1 })),
|
||||||
);
|
tx
|
||||||
|
);
|
||||||
|
}
|
||||||
await projectRoleDAL.insertMany(
|
await projectRoleDAL.insertMany(
|
||||||
projectTemplate.packedRoles.map((role) => ({
|
projectTemplate.packedRoles.map((role) => ({
|
||||||
...role,
|
...role,
|
||||||
@@ -592,7 +594,10 @@ export const projectServiceFactory = ({
|
|||||||
workspaces.map(async (workspace) => {
|
workspaces.map(async (workspace) => {
|
||||||
return {
|
return {
|
||||||
...workspace,
|
...workspace,
|
||||||
roles: [...(workspaceMappedToRoles[workspace.id] || []), ...getPredefinedRoles(workspace.id)]
|
roles: [
|
||||||
|
...(workspaceMappedToRoles[workspace.id] || []),
|
||||||
|
...getPredefinedRoles({ projectId: workspace.id, projectType: workspace.type as ProjectType })
|
||||||
|
]
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ In the following steps, we'll explore how to set up a project template.
|
|||||||
<Tab title="Infisical UI">
|
<Tab title="Infisical UI">
|
||||||
<Steps>
|
<Steps>
|
||||||
<Step title="Creating a Project Template">
|
<Step title="Creating a Project Template">
|
||||||
Navigate to the Project Templates tab on the Organization Settings page and tap on the **Add Template** button.
|
Navigate to the **Project Templates** tab on the Feature Settings page for the project type you want to create a template for and tap on the **Add Template** button.
|
||||||

|

|
||||||
|
|
||||||
Specify your template details. Here's some guidance on each field:
|
Specify your template details. Here's some guidance on each field:
|
||||||
@@ -67,6 +67,7 @@ In the following steps, we'll explore how to set up a project template.
|
|||||||
--header 'Content-Type: application/json' \
|
--header 'Content-Type: application/json' \
|
||||||
--data '{
|
--data '{
|
||||||
"name": "my-project-template",
|
"name": "my-project-template",
|
||||||
|
"type": "secret-manager",
|
||||||
"description": "...",
|
"description": "...",
|
||||||
"environments": "[...]",
|
"environments": "[...]",
|
||||||
"roles": "[...]",
|
"roles": "[...]",
|
||||||
|
|||||||
@@ -31,16 +31,9 @@ we will register a remote host with Infisical through a [machine identity](/docu
|
|||||||
|
|
||||||
<Steps>
|
<Steps>
|
||||||
<Step title="Create an Infisical SSH project">
|
<Step title="Create an Infisical SSH project">
|
||||||
1.1. Start by creating a new Infisical SSH project in Infisical.
|
Start by creating a new Infisical SSH project in Infisical.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
1.2. Create a custom role in the project under Access Control > Project Roles to grant the machine identity that we will create in step 2 the ability to **Create** and **Issue Host Certificates** on the **SSH Host** resource; this will enable the linked machine identity to bootstrap a remote host with Infisical
|
|
||||||
and establish the necessary configuration on it.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|
|
||||||
</Step>
|
</Step>
|
||||||
<Step title="Create a machine identity for bootstrapping Infisical SSH">
|
<Step title="Create a machine identity for bootstrapping Infisical SSH">
|
||||||
2.1. Follow the instructions [here](/documentation/platform/identities/universal-auth) to configure a [machine identity](/documentation/platform/identities/machine-identities) in Infisical with Universal Auth.
|
2.1. Follow the instructions [here](/documentation/platform/identities/universal-auth) to configure a [machine identity](/documentation/platform/identities/machine-identities) in Infisical with Universal Auth.
|
||||||
@@ -52,7 +45,14 @@ we will register a remote host with Infisical through a [machine identity](/docu
|
|||||||
You may use other authentication methods as suitable (e.g. [AWS Auth](/documentation/platform/identities/aws-auth), [Azure Auth](/documentation/platform/identities/azure-auth), [GCP Auth](/documentation/platform/identities/gcp-auth), etc.) as part of the machine identity configuration but, to keep this example simple, we will be using Universal Auth.
|
You may use other authentication methods as suitable (e.g. [AWS Auth](/documentation/platform/identities/aws-auth), [Azure Auth](/documentation/platform/identities/azure-auth), [GCP Auth](/documentation/platform/identities/gcp-auth), etc.) as part of the machine identity configuration but, to keep this example simple, we will be using Universal Auth.
|
||||||
</Note>
|
</Note>
|
||||||
|
|
||||||
2.2. Add the machine identity to the Infisical SSH project you created in the previous step and assign it the custom role you created in step 1.2.
|
2.2. Add the machine identity to the Infisical SSH project you created in the previous step and assign it the **SSH Host Bootstrapper** role.
|
||||||
|
|
||||||
|
This role grants the ability to **Create** and **Issue Host Certificates** on the **SSH Host** resource; this will enable the linked machine identity to bootstrap a remote host with Infisical
|
||||||
|
and establish the necessary configuration on it.
|
||||||
|
|
||||||
|
<Tip>
|
||||||
|
If you plan to use a custom role to bootstrap SSH hosts, ensure the role has the **Create** and **Issue Host Certificates** on the **SSH Host** resource.
|
||||||
|
</Tip>
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 951 KiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 579 KiB After Width: | Height: | Size: 687 KiB |
|
Before Width: | Height: | Size: 562 KiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1015 KiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 852 KiB |
|
Before Width: | Height: | Size: 564 KiB After Width: | Height: | Size: 680 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
@@ -72,7 +72,7 @@ const NewProjectForm = ({ onOpenChange, projectType }: NewProjectFormProps) => {
|
|||||||
OrgPermissionSubjects.ProjectTemplates
|
OrgPermissionSubjects.ProjectTemplates
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data: projectTemplates = [] } = useListProjectTemplates({
|
const { data: projectTemplates = [] } = useListProjectTemplates(projectType, {
|
||||||
enabled: Boolean(canReadProjectTemplates && subscription?.projectTemplates)
|
enabled: Boolean(canReadProjectTemplates && subscription?.projectTemplates)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import { Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
|
||||||
|
|
||||||
|
import { ProjectTemplatesTab } from "./components";
|
||||||
|
|
||||||
|
const tabs = [
|
||||||
|
{ name: "Project Templates", key: "project-templates", component: ProjectTemplatesTab }
|
||||||
|
];
|
||||||
|
|
||||||
|
export const ProjectSettings = () => {
|
||||||
|
const [selectedTab, setSelectedTab] = useState(tabs[0].key);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tabs value={selectedTab} onValueChange={setSelectedTab}>
|
||||||
|
<TabList>
|
||||||
|
{tabs.map((tab) => (
|
||||||
|
<Tab value={tab.key} key={tab.key}>
|
||||||
|
{tab.name}
|
||||||
|
</Tab>
|
||||||
|
))}
|
||||||
|
</TabList>
|
||||||
|
{tabs.map(({ key, component: Component }) => (
|
||||||
|
<TabPanel value={key} key={`tab-panel-${key}`}>
|
||||||
|
<Component />
|
||||||
|
</TabPanel>
|
||||||
|
))}
|
||||||
|
</Tabs>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -7,6 +7,7 @@ import { Button, DeleteActionModal } from "@app/components/v2";
|
|||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
|
||||||
import { usePopUp } from "@app/hooks";
|
import { usePopUp } from "@app/hooks";
|
||||||
import { TProjectTemplate, useDeleteProjectTemplate } from "@app/hooks/api/projectTemplates";
|
import { TProjectTemplate, useDeleteProjectTemplate } from "@app/hooks/api/projectTemplates";
|
||||||
|
import { ProjectType } from "@app/hooks/api/workspace/types";
|
||||||
|
|
||||||
import { ProjectTemplateDetailsModal } from "../../ProjectTemplateDetailsModal";
|
import { ProjectTemplateDetailsModal } from "../../ProjectTemplateDetailsModal";
|
||||||
import { ProjectTemplateEnvironmentsForm } from "./ProjectTemplateEnvironmentsForm";
|
import { ProjectTemplateEnvironmentsForm } from "./ProjectTemplateEnvironmentsForm";
|
||||||
@@ -24,7 +25,7 @@ export const EditProjectTemplate = ({ isInfisicalTemplate, projectTemplate, onBa
|
|||||||
"editDetails"
|
"editDetails"
|
||||||
] as const);
|
] as const);
|
||||||
|
|
||||||
const { id: templateId, name, description } = projectTemplate;
|
const { id: templateId, name, description, type } = projectTemplate;
|
||||||
|
|
||||||
const deleteProjectTemplate = useDeleteProjectTemplate();
|
const deleteProjectTemplate = useDeleteProjectTemplate();
|
||||||
|
|
||||||
@@ -94,10 +95,12 @@ export const EditProjectTemplate = ({ isInfisicalTemplate, projectTemplate, onBa
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<ProjectTemplateEnvironmentsForm
|
{type === ProjectType.SecretManager && (
|
||||||
isInfisicalTemplate={isInfisicalTemplate}
|
<ProjectTemplateEnvironmentsForm
|
||||||
projectTemplate={projectTemplate}
|
isInfisicalTemplate={isInfisicalTemplate}
|
||||||
/>
|
projectTemplate={projectTemplate}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<ProjectTemplateRolesSection
|
<ProjectTemplateRolesSection
|
||||||
isInfisicalTemplate={isInfisicalTemplate}
|
isInfisicalTemplate={isInfisicalTemplate}
|
||||||
projectTemplate={projectTemplate}
|
projectTemplate={projectTemplate}
|
||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
THead,
|
THead,
|
||||||
Tr
|
Tr
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
|
import { OrgPermissionActions, OrgPermissionSubjects, useSubscription } from "@app/context";
|
||||||
import { TProjectTemplate, useUpdateProjectTemplate } from "@app/hooks/api/projectTemplates";
|
import { TProjectTemplate, useUpdateProjectTemplate } from "@app/hooks/api/projectTemplates";
|
||||||
import { slugSchema } from "@app/lib/schemas";
|
import { slugSchema } from "@app/lib/schemas";
|
||||||
|
|
||||||
@@ -35,6 +35,7 @@ const formSchema = z.object({
|
|||||||
slug: slugSchema({ min: 1, max: 32 })
|
slug: slugSchema({ min: 1, max: 32 })
|
||||||
})
|
})
|
||||||
.array()
|
.array()
|
||||||
|
.nullish()
|
||||||
});
|
});
|
||||||
|
|
||||||
type TFormSchema = z.infer<typeof formSchema>;
|
type TFormSchema = z.infer<typeof formSchema>;
|
||||||
@@ -55,6 +56,8 @@ export const ProjectTemplateEnvironmentsForm = ({
|
|||||||
resolver: zodResolver(formSchema)
|
resolver: zodResolver(formSchema)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { subscription } = useSubscription();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
fields: environments,
|
fields: environments,
|
||||||
move,
|
move,
|
||||||
@@ -67,7 +70,7 @@ export const ProjectTemplateEnvironmentsForm = ({
|
|||||||
const onFormSubmit = async (form: TFormSchema) => {
|
const onFormSubmit = async (form: TFormSchema) => {
|
||||||
try {
|
try {
|
||||||
const { environments: updatedEnvs } = await updateProjectTemplate.mutateAsync({
|
const { environments: updatedEnvs } = await updateProjectTemplate.mutateAsync({
|
||||||
environments: form.environments.map((env, index) => ({
|
environments: form.environments?.map((env, index) => ({
|
||||||
...env,
|
...env,
|
||||||
position: index + 1
|
position: index + 1
|
||||||
})),
|
})),
|
||||||
@@ -89,6 +92,9 @@ export const ProjectTemplateEnvironmentsForm = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isEnvironmentLimitExceeded =
|
||||||
|
Boolean(subscription.environmentLimit) && environments.length >= subscription.environmentLimit;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit(onFormSubmit)}
|
onSubmit={handleSubmit(onFormSubmit)}
|
||||||
@@ -138,6 +144,8 @@ export const ProjectTemplateEnvironmentsForm = ({
|
|||||||
<OrgPermissionCan
|
<OrgPermissionCan
|
||||||
I={OrgPermissionActions.Edit}
|
I={OrgPermissionActions.Edit}
|
||||||
a={OrgPermissionSubjects.ProjectTemplates}
|
a={OrgPermissionSubjects.ProjectTemplates}
|
||||||
|
renderTooltip={isEnvironmentLimitExceeded ? true : undefined}
|
||||||
|
allowedLabel={`Plan environment limit of ${subscription.environmentLimit} exceeded. Contact Infisical to increase limit.`}
|
||||||
>
|
>
|
||||||
{(isAllowed) => (
|
{(isAllowed) => (
|
||||||
<Button
|
<Button
|
||||||
@@ -147,7 +155,7 @@ export const ProjectTemplateEnvironmentsForm = ({
|
|||||||
variant="solid"
|
variant="solid"
|
||||||
size="xs"
|
size="xs"
|
||||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||||
isDisabled={!isAllowed}
|
isDisabled={!isAllowed || isEnvironmentLimitExceeded}
|
||||||
>
|
>
|
||||||
Add Environment
|
Add Environment
|
||||||
</Button>
|
</Button>
|
||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
ModalContent,
|
ModalContent,
|
||||||
TextArea
|
TextArea
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
|
import { useGetProjectTypeFromRoute } from "@app/hooks";
|
||||||
import {
|
import {
|
||||||
TProjectTemplate,
|
TProjectTemplate,
|
||||||
useCreateProjectTemplate,
|
useCreateProjectTemplate,
|
||||||
@@ -41,6 +42,7 @@ type FormProps = {
|
|||||||
const ProjectTemplateForm = ({ onComplete, projectTemplate }: FormProps) => {
|
const ProjectTemplateForm = ({ onComplete, projectTemplate }: FormProps) => {
|
||||||
const createProjectTemplate = useCreateProjectTemplate();
|
const createProjectTemplate = useCreateProjectTemplate();
|
||||||
const updateProjectTemplate = useUpdateProjectTemplate();
|
const updateProjectTemplate = useUpdateProjectTemplate();
|
||||||
|
const projectType = useGetProjectTypeFromRoute();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@@ -55,9 +57,17 @@ const ProjectTemplateForm = ({ onComplete, projectTemplate }: FormProps) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const onFormSubmit = async (data: FormData) => {
|
const onFormSubmit = async (data: FormData) => {
|
||||||
|
if (!projectType) {
|
||||||
|
createNotification({
|
||||||
|
text: "Failed to determine project type",
|
||||||
|
type: "error"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const mutation = projectTemplate
|
const mutation = projectTemplate
|
||||||
? updateProjectTemplate.mutateAsync({ templateId: projectTemplate.id, ...data })
|
? updateProjectTemplate.mutateAsync({ templateId: projectTemplate.id, ...data })
|
||||||
: createProjectTemplate.mutateAsync(data);
|
: createProjectTemplate.mutateAsync({ ...data, type: projectType });
|
||||||
try {
|
try {
|
||||||
const template = await mutation;
|
const template = await mutation;
|
||||||
createNotification({
|
createNotification({
|
||||||
@@ -50,7 +50,7 @@ export const ProjectTemplatesSection = () => {
|
|||||||
className="absolute min-h-[10rem] w-full"
|
className="absolute min-h-[10rem] w-full"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p className="mb-6 text-bunker-300">
|
<p className="mb-6 font-inter text-bunker-300">
|
||||||
Create and configure templates with predefined roles and environments to streamline
|
Create and configure templates with predefined roles and environments to streamline
|
||||||
project setup
|
project setup
|
||||||
</p>
|
</p>
|
||||||
@@ -23,7 +23,7 @@ import {
|
|||||||
Tr
|
Tr
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects, useSubscription } from "@app/context";
|
import { OrgPermissionActions, OrgPermissionSubjects, useSubscription } from "@app/context";
|
||||||
import { usePopUp } from "@app/hooks";
|
import { useGetProjectTypeFromRoute, usePopUp } from "@app/hooks";
|
||||||
import { TProjectTemplate, useListProjectTemplates } from "@app/hooks/api/projectTemplates";
|
import { TProjectTemplate, useListProjectTemplates } from "@app/hooks/api/projectTemplates";
|
||||||
|
|
||||||
import { DeleteProjectTemplateModal } from "./DeleteProjectTemplateModal";
|
import { DeleteProjectTemplateModal } from "./DeleteProjectTemplateModal";
|
||||||
@@ -35,8 +35,10 @@ type Props = {
|
|||||||
export const ProjectTemplatesTable = ({ onEdit }: Props) => {
|
export const ProjectTemplatesTable = ({ onEdit }: Props) => {
|
||||||
const { subscription } = useSubscription();
|
const { subscription } = useSubscription();
|
||||||
|
|
||||||
const { isPending, data: projectTemplates = [] } = useListProjectTemplates({
|
const projectType = useGetProjectTypeFromRoute();
|
||||||
enabled: subscription?.projectTemplates
|
|
||||||
|
const { isPending, data: projectTemplates = [] } = useListProjectTemplates(projectType, {
|
||||||
|
enabled: subscription?.projectTemplates && Boolean(projectType)
|
||||||
});
|
});
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
|
|
||||||
@@ -50,6 +52,8 @@ export const ProjectTemplatesTable = ({ onEdit }: Props) => {
|
|||||||
[search, projectTemplates]
|
[search, projectTemplates]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isSecretManagerTemplates = projectType === "secret-manager";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Input
|
<Input
|
||||||
@@ -64,7 +68,7 @@ export const ProjectTemplatesTable = ({ onEdit }: Props) => {
|
|||||||
<Tr>
|
<Tr>
|
||||||
<Th>Name</Th>
|
<Th>Name</Th>
|
||||||
<Th>Roles</Th>
|
<Th>Roles</Th>
|
||||||
<Th>Environments</Th>
|
{isSecretManagerTemplates && <Th>Environments</Th>}
|
||||||
<Th />
|
<Th />
|
||||||
</Tr>
|
</Tr>
|
||||||
</THead>
|
</THead>
|
||||||
@@ -77,7 +81,7 @@ export const ProjectTemplatesTable = ({ onEdit }: Props) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{filteredTemplates.map((template) => {
|
{filteredTemplates.map((template) => {
|
||||||
const { id, name, roles, environments, description } = template;
|
const { id, name, roles, environments = [], description } = template;
|
||||||
return (
|
return (
|
||||||
<Tr
|
<Tr
|
||||||
onClick={() => onEdit(template)}
|
onClick={() => onEdit(template)}
|
||||||
@@ -116,28 +120,30 @@ export const ProjectTemplatesTable = ({ onEdit }: Props) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</Td>
|
</Td>
|
||||||
<Td className="pl-14">
|
{isSecretManagerTemplates && environments && (
|
||||||
{environments.length}
|
<Td className="pl-14">
|
||||||
{environments.length > 0 && (
|
{environments.length}
|
||||||
<Tooltip
|
{environments.length > 0 && (
|
||||||
content={
|
<Tooltip
|
||||||
<ul className="ml-2 list-disc">
|
content={
|
||||||
{environments
|
<ul className="ml-2 list-disc">
|
||||||
.sort((a, b) => (a.position > b.position ? 1 : -1))
|
{environments
|
||||||
.map((env) => (
|
.sort((a, b) => (a.position > b.position ? 1 : -1))
|
||||||
<li key={env.slug}>{env.name}</li>
|
.map((env) => (
|
||||||
))}
|
<li key={env.slug}>{env.name}</li>
|
||||||
</ul>
|
))}
|
||||||
}
|
</ul>
|
||||||
>
|
}
|
||||||
<FontAwesomeIcon
|
>
|
||||||
size="sm"
|
<FontAwesomeIcon
|
||||||
className="ml-2 text-mineshaft-400"
|
size="sm"
|
||||||
icon={faCircleInfo}
|
className="ml-2 text-mineshaft-400"
|
||||||
/>
|
icon={faCircleInfo}
|
||||||
</Tooltip>
|
/>
|
||||||
)}
|
</Tooltip>
|
||||||
</Td>
|
)}
|
||||||
|
</Td>
|
||||||
|
)}
|
||||||
<Td className="w-5">
|
<Td className="w-5">
|
||||||
{name !== "default" && (
|
{name !== "default" && (
|
||||||
<OrgPermissionCan
|
<OrgPermissionCan
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from "./ProjectTemplatesTab";
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from "./ProjectSettings";
|
||||||
@@ -6,21 +6,9 @@ export enum OrgMembershipRole {
|
|||||||
NoAccess = "no-access"
|
NoAccess = "no-access"
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ProjectMemberRole {
|
|
||||||
Admin = "admin",
|
|
||||||
Member = "member",
|
|
||||||
Viewer = "viewer",
|
|
||||||
NoAccess = "no-access"
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isCustomOrgRole = (slug: string) =>
|
export const isCustomOrgRole = (slug: string) =>
|
||||||
!Object.values(OrgMembershipRole).includes(slug as OrgMembershipRole);
|
!Object.values(OrgMembershipRole).includes(slug as OrgMembershipRole);
|
||||||
|
|
||||||
export const formatProjectRoleName = (name: string) => {
|
|
||||||
if (name === ProjectMemberRole.Member) return "developer";
|
|
||||||
return name;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const isCustomProjectRole = (slug: string) =>
|
export const isCustomProjectRole = (slug: string) =>
|
||||||
!Object.values(ProjectMembershipRole).includes(slug as ProjectMembershipRole);
|
!Object.values(ProjectMembershipRole).includes(slug as ProjectMembershipRole);
|
||||||
|
|
||||||
@@ -28,3 +16,24 @@ export const findOrgMembershipRole = (roles: TOrgRole[], roleIdOrSlug: string) =
|
|||||||
isCustomOrgRole(roleIdOrSlug)
|
isCustomOrgRole(roleIdOrSlug)
|
||||||
? roles.find((r) => r.id === roleIdOrSlug)
|
? roles.find((r) => r.id === roleIdOrSlug)
|
||||||
: roles.find((r) => r.slug === roleIdOrSlug);
|
: roles.find((r) => r.slug === roleIdOrSlug);
|
||||||
|
|
||||||
|
export const formatProjectRoleName = (role: string, customRoleName?: string) => {
|
||||||
|
switch (role) {
|
||||||
|
case ProjectMembershipRole.Admin:
|
||||||
|
return "Admin";
|
||||||
|
case ProjectMembershipRole.Member:
|
||||||
|
return "Developer";
|
||||||
|
case ProjectMembershipRole.Viewer:
|
||||||
|
return "Viewer";
|
||||||
|
case ProjectMembershipRole.NoAccess:
|
||||||
|
return "No Access";
|
||||||
|
case ProjectMembershipRole.Custom:
|
||||||
|
return customRoleName ?? role;
|
||||||
|
case ProjectMembershipRole.SshHostBootstrapper:
|
||||||
|
return "SSH Host Bootstrapper";
|
||||||
|
case ProjectMembershipRole.KmsCryptographicOperator:
|
||||||
|
return "Cryptographic Operator";
|
||||||
|
default:
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -6,14 +6,17 @@ import {
|
|||||||
TProjectTemplate,
|
TProjectTemplate,
|
||||||
TProjectTemplateResponse
|
TProjectTemplateResponse
|
||||||
} from "@app/hooks/api/projectTemplates/types";
|
} from "@app/hooks/api/projectTemplates/types";
|
||||||
|
import { ProjectType } from "@app/hooks/api/workspace/types";
|
||||||
|
|
||||||
export const projectTemplateKeys = {
|
export const projectTemplateKeys = {
|
||||||
all: ["project-template"] as const,
|
all: ["project-template"] as const,
|
||||||
list: () => [...projectTemplateKeys.all, "list"] as const,
|
list: (projectType?: ProjectType) =>
|
||||||
|
[...projectTemplateKeys.all, "list", ...(projectType ? [projectType] : [])] as const,
|
||||||
byId: (templateId: string) => [...projectTemplateKeys.all, templateId] as const
|
byId: (templateId: string) => [...projectTemplateKeys.all, templateId] as const
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useListProjectTemplates = (
|
export const useListProjectTemplates = (
|
||||||
|
type?: ProjectType,
|
||||||
options?: Omit<
|
options?: Omit<
|
||||||
UseQueryOptions<
|
UseQueryOptions<
|
||||||
TProjectTemplate[],
|
TProjectTemplate[],
|
||||||
@@ -25,9 +28,11 @@ export const useListProjectTemplates = (
|
|||||||
>
|
>
|
||||||
) => {
|
) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: projectTemplateKeys.list(),
|
queryKey: projectTemplateKeys.list(type),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await apiRequest.get<TListProjectTemplates>("/api/v1/project-templates");
|
const { data } = await apiRequest.get<TListProjectTemplates>("/api/v1/project-templates", {
|
||||||
|
params: { type }
|
||||||
|
});
|
||||||
|
|
||||||
return data.projectTemplates;
|
return data.projectTemplates;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { TProjectRole } from "@app/hooks/api/roles/types";
|
import { TProjectRole } from "@app/hooks/api/roles/types";
|
||||||
|
import { ProjectType } from "@app/hooks/api/workspace/types";
|
||||||
|
|
||||||
export type TProjectTemplate = {
|
export type TProjectTemplate = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
type: ProjectType;
|
||||||
description?: string;
|
description?: string;
|
||||||
roles: Pick<TProjectRole, "slug" | "name" | "permissions">[];
|
roles: Pick<TProjectRole, "slug" | "name" | "permissions">[];
|
||||||
environments: { name: string; slug: string; position: number }[];
|
environments?: { name: string; slug: string; position: number }[] | null;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
};
|
};
|
||||||
@@ -14,6 +16,7 @@ export type TListProjectTemplates = { projectTemplates: TProjectTemplate[] };
|
|||||||
export type TProjectTemplateResponse = { projectTemplate: TProjectTemplate };
|
export type TProjectTemplateResponse = { projectTemplate: TProjectTemplate };
|
||||||
|
|
||||||
export type TCreateProjectTemplateDTO = {
|
export type TCreateProjectTemplateDTO = {
|
||||||
|
type: ProjectType;
|
||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ export enum ProjectMembershipRole {
|
|||||||
Member = "member",
|
Member = "member",
|
||||||
Custom = "custom",
|
Custom = "custom",
|
||||||
Viewer = "viewer",
|
Viewer = "viewer",
|
||||||
NoAccess = "no-access"
|
NoAccess = "no-access",
|
||||||
|
SshHostBootstrapper = "ssh-host-bootstrapper",
|
||||||
|
KmsCryptographicOperator = "cryptographic-operator"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TGetProjectRolesDTO = {
|
export type TGetProjectRolesDTO = {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export { useDebounce } from "./useDebounce";
|
export { useDebounce } from "./useDebounce";
|
||||||
|
export * from "./useGetProjectTypeFromRoute";
|
||||||
export { usePagination } from "./usePagination";
|
export { usePagination } from "./usePagination";
|
||||||
export { usePersistentState } from "./usePersistentState";
|
export { usePersistentState } from "./usePersistentState";
|
||||||
export { usePopUp } from "./usePopUp";
|
export { usePopUp } from "./usePopUp";
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { useRouterState } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
import { ProjectType } from "@app/hooks/api/workspace/types";
|
||||||
|
|
||||||
|
export const useGetProjectTypeFromRoute = () => {
|
||||||
|
const { location } = useRouterState();
|
||||||
|
|
||||||
|
const segment = location.pathname.split("/")[2];
|
||||||
|
|
||||||
|
if (!Object.values(ProjectType).includes(segment as ProjectType)) return undefined;
|
||||||
|
|
||||||
|
return segment as ProjectType;
|
||||||
|
};
|
||||||
@@ -11,11 +11,12 @@ import { BreadcrumbContainer, TBreadcrumbFormat } from "@app/components/v2";
|
|||||||
import { OrgPermissionSubjects, useOrgPermission, useServerConfig } from "@app/context";
|
import { OrgPermissionSubjects, useOrgPermission, useServerConfig } from "@app/context";
|
||||||
import { OrgPermissionSecretShareAction } from "@app/context/OrgPermissionContext/types";
|
import { OrgPermissionSecretShareAction } from "@app/context/OrgPermissionContext/types";
|
||||||
import { usePopUp } from "@app/hooks";
|
import { usePopUp } from "@app/hooks";
|
||||||
|
import { ProjectType } from "@app/hooks/api/workspace/types";
|
||||||
|
|
||||||
import { InsecureConnectionBanner } from "./components/InsecureConnectionBanner";
|
import { InsecureConnectionBanner } from "./components/InsecureConnectionBanner";
|
||||||
import { MinimizedOrgSidebar } from "./components/MinimizedOrgSidebar";
|
import { MinimizedOrgSidebar } from "./components/MinimizedOrgSidebar";
|
||||||
import { SidebarHeader } from "./components/SidebarHeader";
|
import { SidebarHeader } from "./components/SidebarHeader";
|
||||||
import { DefaultSideBar, SecretSharingSideBar } from "./ProductsSideBar";
|
import { DefaultSideBar, ProjectOverviewSideBar, SecretSharingSideBar } from "./ProductsSideBar";
|
||||||
|
|
||||||
export const OrganizationLayout = () => {
|
export const OrganizationLayout = () => {
|
||||||
const matches = useRouterState({ select: (s) => s.matches.at(-1)?.context });
|
const matches = useRouterState({ select: (s) => s.matches.at(-1)?.context });
|
||||||
@@ -45,21 +46,38 @@ export const OrganizationLayout = () => {
|
|||||||
] as string[]
|
] as string[]
|
||||||
).includes(location.pathname);
|
).includes(location.pathname);
|
||||||
|
|
||||||
|
const isProjectOverviewOrSettingsPage = (
|
||||||
|
[
|
||||||
|
linkOptions({ to: "/organization/secret-manager/overview" }).to,
|
||||||
|
linkOptions({ to: "/organization/secret-manager/settings" }).to,
|
||||||
|
linkOptions({ to: "/organization/cert-manager/overview" }).to,
|
||||||
|
linkOptions({ to: "/organization/cert-manager/settings" }).to,
|
||||||
|
linkOptions({ to: "/organization/kms/overview" }).to,
|
||||||
|
linkOptions({ to: "/organization/kms/settings" }).to,
|
||||||
|
linkOptions({ to: "/organization/ssh/overview" }).to,
|
||||||
|
linkOptions({ to: "/organization/ssh/settings" }).to
|
||||||
|
] as string[]
|
||||||
|
).includes(location.pathname);
|
||||||
|
|
||||||
const shouldShowOrgSidebar =
|
const shouldShowOrgSidebar =
|
||||||
location.pathname.startsWith("/organization") &&
|
location.pathname.startsWith("/organization") &&
|
||||||
(!isSecretSharingPage || shouldShowProductsSidebar) &&
|
(!isSecretSharingPage || shouldShowProductsSidebar) &&
|
||||||
!(
|
!([linkOptions({ to: "/organization/secret-scanning" }).to] as string[]).includes(
|
||||||
[
|
location.pathname
|
||||||
linkOptions({ to: "/organization/secret-manager/overview" }).to,
|
);
|
||||||
linkOptions({ to: "/organization/cert-manager/overview" }).to,
|
|
||||||
linkOptions({ to: "/organization/ssh/overview" }).to,
|
|
||||||
linkOptions({ to: "/organization/kms/overview" }).to,
|
|
||||||
linkOptions({ to: "/organization/secret-scanning" }).to
|
|
||||||
] as string[]
|
|
||||||
).includes(location.pathname);
|
|
||||||
|
|
||||||
const containerHeight = config.pageFrameContent ? "h-[94vh]" : "h-screen";
|
const containerHeight = config.pageFrameContent ? "h-[94vh]" : "h-screen";
|
||||||
|
|
||||||
|
let SideBarComponent = <DefaultSideBar />;
|
||||||
|
|
||||||
|
if (isSecretSharingPage) {
|
||||||
|
SideBarComponent = <SecretSharingSideBar />;
|
||||||
|
} else if (isProjectOverviewOrSettingsPage) {
|
||||||
|
SideBarComponent = (
|
||||||
|
<ProjectOverviewSideBar type={location.pathname.split("/")[2] as ProjectType} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Banner />
|
<Banner />
|
||||||
@@ -80,10 +98,12 @@ export const OrganizationLayout = () => {
|
|||||||
className="dark w-60 overflow-hidden border-r border-mineshaft-600 bg-gradient-to-tr from-mineshaft-700 via-mineshaft-800 to-mineshaft-900"
|
className="dark w-60 overflow-hidden border-r border-mineshaft-600 bg-gradient-to-tr from-mineshaft-700 via-mineshaft-800 to-mineshaft-900"
|
||||||
>
|
>
|
||||||
<nav className="items-between flex h-full flex-col overflow-y-auto dark:[color-scheme:dark]">
|
<nav className="items-between flex h-full flex-col overflow-y-auto dark:[color-scheme:dark]">
|
||||||
<div className="p-2 pt-3">
|
{!isProjectOverviewOrSettingsPage && (
|
||||||
<SidebarHeader />
|
<div className="p-2 pt-3">
|
||||||
</div>
|
<SidebarHeader />
|
||||||
{isSecretSharingPage ? <SecretSharingSideBar /> : <DefaultSideBar />}
|
</div>
|
||||||
|
)}
|
||||||
|
{SideBarComponent}
|
||||||
</nav>
|
</nav>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
import { faArrowUpRightFromSquare } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { Link, useMatchRoute } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
import { Menu, MenuGroup, MenuItem } from "@app/components/v2";
|
||||||
|
import { ProjectType } from "@app/hooks/api/workspace/types";
|
||||||
|
|
||||||
|
type TProjectOverviewSideBarProps = {
|
||||||
|
type: ProjectType;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ProjectOverviewSideBar = ({ type }: TProjectOverviewSideBarProps) => {
|
||||||
|
const matchRoute = useMatchRoute();
|
||||||
|
|
||||||
|
const isOverviewActive = !!matchRoute({
|
||||||
|
to: `/organization/${type}/overview`,
|
||||||
|
fuzzy: false
|
||||||
|
});
|
||||||
|
|
||||||
|
let label: string;
|
||||||
|
let icon: string;
|
||||||
|
let link: string;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ProjectType.CertificateManager:
|
||||||
|
label = "Cert Management";
|
||||||
|
icon = "note";
|
||||||
|
link = "https://infisical.com/docs/documentation/platform/pki/overview";
|
||||||
|
break;
|
||||||
|
case ProjectType.SecretManager:
|
||||||
|
label = "Secret Management";
|
||||||
|
icon = "sliding-carousel";
|
||||||
|
link = "https://infisical.com/docs/documentation/getting-started/introduction";
|
||||||
|
break;
|
||||||
|
case ProjectType.KMS:
|
||||||
|
label = "KMS";
|
||||||
|
icon = "unlock";
|
||||||
|
link = "https://infisical.com/docs/documentation/platform/kms/overview";
|
||||||
|
break;
|
||||||
|
case ProjectType.SSH:
|
||||||
|
label = "SSH";
|
||||||
|
icon = "verified";
|
||||||
|
link = "https://infisical.com/docs/documentation/platform/ssh/overview";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("Unknown project type");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="p-2 pt-3">
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
href={link}
|
||||||
|
className="flex w-full items-center rounded-md border border-mineshaft-600 p-2 pl-3 transition-all duration-150 hover:bg-mineshaft-700"
|
||||||
|
>
|
||||||
|
<div className="mr-2 flex h-6 w-6 items-center justify-center rounded-md bg-mineshaft-500 p-4">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faArrowUpRightFromSquare}
|
||||||
|
className="h-3.5 w-3.5 text-mineshaft-300"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="-mt-1 flex flex-grow flex-col text-white">
|
||||||
|
<div className="max-w-36 truncate text-ellipsis text-sm font-medium capitalize">
|
||||||
|
Infisical Docs
|
||||||
|
</div>
|
||||||
|
<div className="text-xs leading-[10px] text-mineshaft-400">
|
||||||
|
{type === ProjectType.SecretManager ? "Get Started" : `${label} Overview`}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<Menu>
|
||||||
|
<MenuGroup title="Overview">
|
||||||
|
<Link to={`/organization/${type}/overview`}>
|
||||||
|
<MenuItem isSelected={isOverviewActive} icon={icon}>
|
||||||
|
{label}
|
||||||
|
</MenuItem>
|
||||||
|
</Link>
|
||||||
|
</MenuGroup>
|
||||||
|
<MenuGroup title="Other">
|
||||||
|
<Link to={`/organization/${type}/settings`}>
|
||||||
|
{({ isActive }) => (
|
||||||
|
<MenuItem isSelected={isActive} icon="toggle-settings">
|
||||||
|
Settings
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
</MenuGroup>
|
||||||
|
</Menu>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from "./DefaultSideBar";
|
export * from "./DefaultSideBar";
|
||||||
|
export * from "./ProjectOverviewSideBar";
|
||||||
export * from "./SecretSharingSideBar";
|
export * from "./SecretSharingSideBar";
|
||||||
|
|||||||
@@ -269,7 +269,9 @@ export const MinimizedOrgSidebar = () => {
|
|||||||
<MenuIconButton
|
<MenuIconButton
|
||||||
isSelected={
|
isSelected={
|
||||||
isActive ||
|
isActive ||
|
||||||
window.location.pathname.startsWith(`/${ProjectType.SecretManager}`)
|
window.location.pathname.startsWith(
|
||||||
|
`/organization/${ProjectType.SecretManager}`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
icon="sliding-carousel"
|
icon="sliding-carousel"
|
||||||
>
|
>
|
||||||
@@ -282,7 +284,9 @@ export const MinimizedOrgSidebar = () => {
|
|||||||
<MenuIconButton
|
<MenuIconButton
|
||||||
isSelected={
|
isSelected={
|
||||||
isActive ||
|
isActive ||
|
||||||
window.location.pathname.startsWith(`/${ProjectType.CertificateManager}`)
|
window.location.pathname.startsWith(
|
||||||
|
`/organization/${ProjectType.CertificateManager}`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
icon="note"
|
icon="note"
|
||||||
>
|
>
|
||||||
@@ -294,7 +298,8 @@ export const MinimizedOrgSidebar = () => {
|
|||||||
{({ isActive }) => (
|
{({ isActive }) => (
|
||||||
<MenuIconButton
|
<MenuIconButton
|
||||||
isSelected={
|
isSelected={
|
||||||
isActive || window.location.pathname.startsWith(`/${ProjectType.KMS}`)
|
isActive ||
|
||||||
|
window.location.pathname.startsWith(`/organization/${ProjectType.KMS}`)
|
||||||
}
|
}
|
||||||
icon="unlock"
|
icon="unlock"
|
||||||
>
|
>
|
||||||
@@ -306,7 +311,8 @@ export const MinimizedOrgSidebar = () => {
|
|||||||
{({ isActive }) => (
|
{({ isActive }) => (
|
||||||
<MenuIconButton
|
<MenuIconButton
|
||||||
isSelected={
|
isSelected={
|
||||||
isActive || window.location.pathname.startsWith(`/${ProjectType.SSH}`)
|
isActive ||
|
||||||
|
window.location.pathname.startsWith(`/organization/${ProjectType.SSH}`)
|
||||||
}
|
}
|
||||||
icon="verified"
|
icon="verified"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { Helmet } from "react-helmet";
|
||||||
|
|
||||||
|
import { ProjectSettings } from "@app/components/projects/ProjectSettings";
|
||||||
|
import { PageHeader } from "@app/components/v2";
|
||||||
|
|
||||||
|
export const CertManagerSettingsPage = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Helmet>
|
||||||
|
<title>Cert Management Settings</title>
|
||||||
|
</Helmet>
|
||||||
|
<div className="flex w-full justify-center bg-bunker-800 text-white">
|
||||||
|
<div className="w-full max-w-7xl">
|
||||||
|
<PageHeader title="Cert Management Settings" />
|
||||||
|
<ProjectSettings />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { faHome } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { createFileRoute, linkOptions } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
import { CertManagerSettingsPage } from "./CertManagerSettingsPage";
|
||||||
|
|
||||||
|
export const Route = createFileRoute(
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/settings"
|
||||||
|
)({
|
||||||
|
component: CertManagerSettingsPage,
|
||||||
|
context: () => ({
|
||||||
|
breadcrumbs: [
|
||||||
|
{
|
||||||
|
label: "Products",
|
||||||
|
icon: () => <FontAwesomeIcon icon={faHome} />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Cert Management",
|
||||||
|
link: linkOptions({ to: "/organization/cert-manager/overview" })
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Settings"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
@@ -6,9 +6,9 @@ import { format } from "date-fns";
|
|||||||
|
|
||||||
import { createNotification } from "@app/components/notifications";
|
import { createNotification } from "@app/components/notifications";
|
||||||
import { IconButton, Tag, Td, Tooltip, Tr } from "@app/components/v2";
|
import { IconButton, Tag, Td, Tooltip, Tr } from "@app/components/v2";
|
||||||
|
import { formatProjectRoleName } from "@app/helpers/roles";
|
||||||
import { useGetUserWorkspaces } from "@app/hooks/api";
|
import { useGetUserWorkspaces } from "@app/hooks/api";
|
||||||
import { IdentityMembership } from "@app/hooks/api/identities/types";
|
import { IdentityMembership } from "@app/hooks/api/identities/types";
|
||||||
import { ProjectMembershipRole } from "@app/hooks/api/roles/types";
|
|
||||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
export enum TabSections {
|
export enum TabSections {
|
||||||
@@ -26,15 +26,6 @@ type Props = {
|
|||||||
) => void;
|
) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatRoleName = (role: string, customRoleName?: string) => {
|
|
||||||
if (role === ProjectMembershipRole.Custom) return customRoleName;
|
|
||||||
if (role === ProjectMembershipRole.Admin) return "Admin";
|
|
||||||
if (role === ProjectMembershipRole.Member) return "Developer";
|
|
||||||
if (role === ProjectMembershipRole.Viewer) return "Viewer";
|
|
||||||
if (role === ProjectMembershipRole.NoAccess) return "No Access";
|
|
||||||
return role;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const IdentityProjectRow = ({
|
export const IdentityProjectRow = ({
|
||||||
membership: { id, createdAt, identity, project, roles },
|
membership: { id, createdAt, identity, project, roles },
|
||||||
handlePopUpOpen
|
handlePopUpOpen
|
||||||
@@ -80,7 +71,7 @@ export const IdentityProjectRow = ({
|
|||||||
<Td>
|
<Td>
|
||||||
<Tag size="xs">{project.type}</Tag>
|
<Tag size="xs">{project.type}</Tag>
|
||||||
</Td>
|
</Td>
|
||||||
<Td>{`${formatRoleName(roles[0].role, roles[0].customRoleName)}${
|
<Td>{`${formatProjectRoleName(roles[0].role, roles[0].customRoleName)}${
|
||||||
roles.length > 1 ? ` (+${roles.length - 1})` : ""
|
roles.length > 1 ? ` (+${roles.length - 1})` : ""
|
||||||
}`}</Td>
|
}`}</Td>
|
||||||
<Td>{format(new Date(createdAt), "yyyy-MM-dd")}</Td>
|
<Td>{format(new Date(createdAt), "yyyy-MM-dd")}</Td>
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { Helmet } from "react-helmet";
|
||||||
|
|
||||||
|
import { ProjectSettings } from "@app/components/projects/ProjectSettings";
|
||||||
|
import { PageHeader } from "@app/components/v2";
|
||||||
|
|
||||||
|
export const KmsSettingsPage = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Helmet>
|
||||||
|
<title>KMS Settings</title>
|
||||||
|
</Helmet>
|
||||||
|
<div className="flex w-full justify-center bg-bunker-800 text-white">
|
||||||
|
<div className="w-full max-w-7xl">
|
||||||
|
<PageHeader title="KMS Settings" />
|
||||||
|
<ProjectSettings />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { faHome } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { createFileRoute, linkOptions } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
import { KmsSettingsPage } from "./KmsSettingsPage";
|
||||||
|
|
||||||
|
export const Route = createFileRoute(
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/kms/settings"
|
||||||
|
)({
|
||||||
|
component: KmsSettingsPage,
|
||||||
|
context: () => ({
|
||||||
|
breadcrumbs: [
|
||||||
|
{
|
||||||
|
label: "Products",
|
||||||
|
icon: () => <FontAwesomeIcon icon={faHome} />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "KMS",
|
||||||
|
link: linkOptions({ to: "/organization/kms/overview" })
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Settings"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
@@ -117,12 +117,8 @@ export const RoleModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
} catch (err) {
|
} catch {
|
||||||
console.error(err);
|
const text = `Failed to ${popUp?.role?.data ? "update" : "create"} role`;
|
||||||
const error = err as any;
|
|
||||||
const text =
|
|
||||||
error?.response?.data?.message ??
|
|
||||||
`Failed to ${popUp?.role?.data ? "update" : "create"} role`;
|
|
||||||
|
|
||||||
createNotification({
|
createNotification({
|
||||||
text,
|
text,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export const ProjectListToggle = ({ value, onChange }: Props) => {
|
|||||||
value={value}
|
value={value}
|
||||||
onValueChange={onChange}
|
onValueChange={onChange}
|
||||||
className="absolute left-0 top-0 h-full w-full cursor-pointer opacity-0"
|
className="absolute left-0 top-0 h-full w-full cursor-pointer opacity-0"
|
||||||
|
dropdownContainerClassName="mt-10 ml-5"
|
||||||
>
|
>
|
||||||
<SelectItem value={ProjectListView.MyProjects}>My Projects</SelectItem>
|
<SelectItem value={ProjectListView.MyProjects}>My Projects</SelectItem>
|
||||||
<SelectItem value={ProjectListView.AllProjects}>All Projects</SelectItem>
|
<SelectItem value={ProjectListView.AllProjects}>All Projects</SelectItem>
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { Helmet } from "react-helmet";
|
||||||
|
|
||||||
|
import { ProjectSettings } from "@app/components/projects/ProjectSettings";
|
||||||
|
import { PageHeader } from "@app/components/v2";
|
||||||
|
|
||||||
|
export const SecretManagerSettingsPage = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Helmet>
|
||||||
|
<title>Secret Management Settings</title>
|
||||||
|
</Helmet>
|
||||||
|
<div className="flex w-full justify-center bg-bunker-800 text-white">
|
||||||
|
<div className="w-full max-w-7xl">
|
||||||
|
<PageHeader title="Secret Management Settings" />
|
||||||
|
<ProjectSettings />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { faHome } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { createFileRoute, linkOptions } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
import { SecretManagerSettingsPage } from "./SecretManagerSettingsPage";
|
||||||
|
|
||||||
|
export const Route = createFileRoute(
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/secret-manager/settings"
|
||||||
|
)({
|
||||||
|
component: SecretManagerSettingsPage,
|
||||||
|
context: () => ({
|
||||||
|
breadcrumbs: [
|
||||||
|
{
|
||||||
|
label: "Products",
|
||||||
|
icon: () => <FontAwesomeIcon icon={faHome} />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Secret Management",
|
||||||
|
link: linkOptions({ to: "/organization/secret-manager/overview" })
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Settings"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
@@ -2,6 +2,7 @@ import { useState } from "react";
|
|||||||
import { useSearch } from "@tanstack/react-router";
|
import { useSearch } from "@tanstack/react-router";
|
||||||
|
|
||||||
import { Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
|
import { Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
|
||||||
|
import { NoticeBannerV2 } from "@app/components/v2/NoticeBannerV2/NoticeBannerV2";
|
||||||
import { ROUTE_PATHS } from "@app/const/routes";
|
import { ROUTE_PATHS } from "@app/const/routes";
|
||||||
|
|
||||||
import { AuditLogStreamsTab } from "../AuditLogStreamTab";
|
import { AuditLogStreamsTab } from "../AuditLogStreamTab";
|
||||||
@@ -11,7 +12,6 @@ import { OrgAuthTab } from "../OrgAuthTab";
|
|||||||
import { OrgEncryptionTab } from "../OrgEncryptionTab";
|
import { OrgEncryptionTab } from "../OrgEncryptionTab";
|
||||||
import { OrgGeneralTab } from "../OrgGeneralTab";
|
import { OrgGeneralTab } from "../OrgGeneralTab";
|
||||||
import { OrgWorkflowIntegrationTab } from "../OrgWorkflowIntegrationTab/OrgWorkflowIntegrationTab";
|
import { OrgWorkflowIntegrationTab } from "../OrgWorkflowIntegrationTab/OrgWorkflowIntegrationTab";
|
||||||
import { ProjectTemplatesTab } from "../ProjectTemplatesTab";
|
|
||||||
|
|
||||||
export const OrgTabGroup = () => {
|
export const OrgTabGroup = () => {
|
||||||
const search = useSearch({
|
const search = useSearch({
|
||||||
@@ -28,7 +28,34 @@ export const OrgTabGroup = () => {
|
|||||||
},
|
},
|
||||||
{ name: "Audit Log Streams", key: "tag-audit-log-streams", component: AuditLogStreamsTab },
|
{ name: "Audit Log Streams", key: "tag-audit-log-streams", component: AuditLogStreamsTab },
|
||||||
{ name: "Import", key: "tab-import", component: ImportTab },
|
{ name: "Import", key: "tab-import", component: ImportTab },
|
||||||
{ name: "Project Templates", key: "project-templates", component: ProjectTemplatesTab },
|
{
|
||||||
|
name: "Project Templates",
|
||||||
|
key: "project-templates",
|
||||||
|
// scott: temporary, remove once users have adjusted
|
||||||
|
// eslint-disable-next-line react/no-unstable-nested-components
|
||||||
|
component: () => (
|
||||||
|
<div>
|
||||||
|
<NoticeBannerV2
|
||||||
|
className="mx-auto mt-10 max-w-4xl"
|
||||||
|
title="Project Templates New Location"
|
||||||
|
>
|
||||||
|
<p className="text-sm text-bunker-200">
|
||||||
|
Project templates have been moved to the Feature Settings page, under the "Project
|
||||||
|
Templates" tab.
|
||||||
|
</p>
|
||||||
|
<p className="mt-2 text-sm text-bunker-200">
|
||||||
|
Project templates are now product-specific, and can be configured for each project
|
||||||
|
type.
|
||||||
|
</p>
|
||||||
|
<img
|
||||||
|
src="/images/project-templates/project-templates-new-location.png"
|
||||||
|
className="mt-4 w-full max-w-4xl rounded"
|
||||||
|
alt="Project Templates New Location"
|
||||||
|
/>
|
||||||
|
</NoticeBannerV2>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
{ name: "KMIP", key: "kmip", component: KmipTab }
|
{ name: "KMIP", key: "kmip", component: KmipTab }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { Helmet } from "react-helmet";
|
||||||
|
|
||||||
|
import { ProjectSettings } from "@app/components/projects/ProjectSettings";
|
||||||
|
import { PageHeader } from "@app/components/v2";
|
||||||
|
|
||||||
|
export const SshSettingsPage = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Helmet>
|
||||||
|
<title>SSH Settings</title>
|
||||||
|
</Helmet>
|
||||||
|
<div className="flex w-full justify-center bg-bunker-800 text-white">
|
||||||
|
<div className="w-full max-w-7xl">
|
||||||
|
<PageHeader title="SSH Settings" />
|
||||||
|
<ProjectSettings />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { faHome } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { createFileRoute, linkOptions } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
import { SshSettingsPage } from "./SshSettingsPage";
|
||||||
|
|
||||||
|
export const Route = createFileRoute(
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/ssh/settings"
|
||||||
|
)({
|
||||||
|
component: SshSettingsPage,
|
||||||
|
context: () => ({
|
||||||
|
breadcrumbs: [
|
||||||
|
{
|
||||||
|
label: "Products",
|
||||||
|
icon: () => <FontAwesomeIcon icon={faHome} />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "SSH",
|
||||||
|
link: linkOptions({ to: "/organization/ssh/overview" })
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Settings"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
});
|
||||||
@@ -5,8 +5,8 @@ import { useNavigate } from "@tanstack/react-router";
|
|||||||
|
|
||||||
import { createNotification } from "@app/components/notifications";
|
import { createNotification } from "@app/components/notifications";
|
||||||
import { IconButton, Tag, Td, Tooltip, Tr } from "@app/components/v2";
|
import { IconButton, Tag, Td, Tooltip, Tr } from "@app/components/v2";
|
||||||
|
import { formatProjectRoleName } from "@app/helpers/roles";
|
||||||
import { useGetUserWorkspaces } from "@app/hooks/api";
|
import { useGetUserWorkspaces } from "@app/hooks/api";
|
||||||
import { ProjectMembershipRole } from "@app/hooks/api/roles/types";
|
|
||||||
import { TWorkspaceUser } from "@app/hooks/api/types";
|
import { TWorkspaceUser } from "@app/hooks/api/types";
|
||||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
import { OrgAccessControlTabSections } from "@app/types/org";
|
import { OrgAccessControlTabSections } from "@app/types/org";
|
||||||
@@ -19,15 +19,6 @@ type Props = {
|
|||||||
) => void;
|
) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatRoleName = (role: string, customRoleName?: string) => {
|
|
||||||
if (role === ProjectMembershipRole.Custom) return customRoleName;
|
|
||||||
if (role === ProjectMembershipRole.Admin) return "Admin";
|
|
||||||
if (role === ProjectMembershipRole.Member) return "Developer";
|
|
||||||
if (role === ProjectMembershipRole.Viewer) return "Viewer";
|
|
||||||
if (role === ProjectMembershipRole.NoAccess) return "No Access";
|
|
||||||
return role;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const UserProjectRow = ({
|
export const UserProjectRow = ({
|
||||||
membership: { id, project, user, roles },
|
membership: { id, project, user, roles },
|
||||||
handlePopUpOpen
|
handlePopUpOpen
|
||||||
@@ -73,7 +64,7 @@ export const UserProjectRow = ({
|
|||||||
<Td>
|
<Td>
|
||||||
<Tag size="xs">{project.type}</Tag>
|
<Tag size="xs">{project.type}</Tag>
|
||||||
</Td>
|
</Td>
|
||||||
<Td>{`${formatRoleName(roles[0].role, roles[0].customRoleName)}${
|
<Td>{`${formatProjectRoleName(roles[0].role, roles[0].customRoleName)}${
|
||||||
roles.length > 1 ? ` (+${roles.length - 1})` : ""
|
roles.length > 1 ? ` (+${roles.length - 1})` : ""
|
||||||
}`}</Td>
|
}`}</Td>
|
||||||
<Td>
|
<Td>
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ import {
|
|||||||
Tooltip
|
Tooltip
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { useWorkspace } from "@app/context";
|
import { useWorkspace } from "@app/context";
|
||||||
|
import { formatProjectRoleName } from "@app/helpers/roles";
|
||||||
import { usePopUp } from "@app/hooks";
|
import { usePopUp } from "@app/hooks";
|
||||||
import { useGetProjectRoles, useUpdateGroupWorkspaceRole } from "@app/hooks/api";
|
import { useGetProjectRoles, useUpdateGroupWorkspaceRole } from "@app/hooks/api";
|
||||||
import { TGroupMembership } from "@app/hooks/api/groups/types";
|
import { TGroupMembership } from "@app/hooks/api/groups/types";
|
||||||
import { ProjectMembershipRole } from "@app/hooks/api/roles/types";
|
|
||||||
import { ProjectUserMembershipTemporaryMode } from "@app/hooks/api/workspace/types";
|
import { ProjectUserMembershipTemporaryMode } from "@app/hooks/api/workspace/types";
|
||||||
import { groupBy } from "@app/lib/fn/array";
|
import { groupBy } from "@app/lib/fn/array";
|
||||||
|
|
||||||
@@ -260,12 +260,6 @@ export const GroupRoles = ({ roles = [], disableEdit = false, groupId }: TMember
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatRoleName = (role: string, customRoleName?: string) => {
|
|
||||||
if (role === ProjectMembershipRole.Custom) return customRoleName;
|
|
||||||
if (role === ProjectMembershipRole.Member) return "Developer";
|
|
||||||
return role;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
{roles
|
{roles
|
||||||
@@ -275,7 +269,7 @@ export const GroupRoles = ({ roles = [], disableEdit = false, groupId }: TMember
|
|||||||
return (
|
return (
|
||||||
<Tag key={id} className="capitalize">
|
<Tag key={id} className="capitalize">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<div>{formatRoleName(role, customRoleName)}</div>
|
<div>{formatProjectRoleName(role, customRoleName)}</div>
|
||||||
{isTemporary && (
|
{isTemporary && (
|
||||||
<div>
|
<div>
|
||||||
<Tooltip content={isExpired ? "Expired Temporary Access" : "Temporary Access"}>
|
<Tooltip content={isExpired ? "Expired Temporary Access" : "Temporary Access"}>
|
||||||
@@ -303,7 +297,7 @@ export const GroupRoles = ({ roles = [], disableEdit = false, groupId }: TMember
|
|||||||
return (
|
return (
|
||||||
<Tag key={id} className="capitalize">
|
<Tag key={id} className="capitalize">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<div>{formatRoleName(role, customRoleName)}</div>
|
<div>{formatProjectRoleName(role, customRoleName)}</div>
|
||||||
{isTemporary && (
|
{isTemporary && (
|
||||||
<div>
|
<div>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
|||||||
@@ -41,11 +41,11 @@ import {
|
|||||||
Tr
|
Tr
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
||||||
|
import { formatProjectRoleName } from "@app/helpers/roles";
|
||||||
import { withProjectPermission } from "@app/hoc";
|
import { withProjectPermission } from "@app/hoc";
|
||||||
import { usePagination, useResetPageHelper } from "@app/hooks";
|
import { usePagination, useResetPageHelper } from "@app/hooks";
|
||||||
import { useDeleteIdentityFromWorkspace, useGetWorkspaceIdentityMemberships } from "@app/hooks/api";
|
import { useDeleteIdentityFromWorkspace, useGetWorkspaceIdentityMemberships } from "@app/hooks/api";
|
||||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||||
import { ProjectMembershipRole } from "@app/hooks/api/roles/types";
|
|
||||||
import { ProjectIdentityOrderBy } from "@app/hooks/api/workspace/types";
|
import { ProjectIdentityOrderBy } from "@app/hooks/api/workspace/types";
|
||||||
import { usePopUp } from "@app/hooks/usePopUp";
|
import { usePopUp } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
@@ -53,12 +53,6 @@ import { IdentityModal } from "./components/IdentityModal";
|
|||||||
|
|
||||||
const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2;
|
const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2;
|
||||||
|
|
||||||
const formatRoleName = (role: string, customRoleName?: string) => {
|
|
||||||
if (role === ProjectMembershipRole.Custom) return customRoleName;
|
|
||||||
if (role === ProjectMembershipRole.Member) return "Developer";
|
|
||||||
if (role === ProjectMembershipRole.NoAccess) return "No access";
|
|
||||||
return role;
|
|
||||||
};
|
|
||||||
export const IdentityTab = withProjectPermission(
|
export const IdentityTab = withProjectPermission(
|
||||||
() => {
|
() => {
|
||||||
const { currentWorkspace } = useWorkspace();
|
const { currentWorkspace } = useWorkspace();
|
||||||
@@ -286,7 +280,7 @@ export const IdentityTab = withProjectPermission(
|
|||||||
<Tag key={roleId}>
|
<Tag key={roleId}>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<div className="capitalize">
|
<div className="capitalize">
|
||||||
{formatRoleName(role, customRoleName)}
|
{formatProjectRoleName(role, customRoleName)}
|
||||||
</div>
|
</div>
|
||||||
{isTemporary && (
|
{isTemporary && (
|
||||||
<div>
|
<div>
|
||||||
@@ -331,7 +325,9 @@ export const IdentityTab = withProjectPermission(
|
|||||||
return (
|
return (
|
||||||
<Tag key={roleId} className="capitalize">
|
<Tag key={roleId} className="capitalize">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<div>{formatRoleName(role, customRoleName)}</div>
|
<div>
|
||||||
|
{formatProjectRoleName(role, customRoleName)}
|
||||||
|
</div>
|
||||||
{isTemporary && (
|
{isTemporary && (
|
||||||
<div>
|
<div>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
|||||||
@@ -50,19 +50,13 @@ import {
|
|||||||
useUser,
|
useUser,
|
||||||
useWorkspace
|
useWorkspace
|
||||||
} from "@app/context";
|
} from "@app/context";
|
||||||
|
import { formatProjectRoleName } from "@app/helpers/roles";
|
||||||
import { usePagination, useResetPageHelper } from "@app/hooks";
|
import { usePagination, useResetPageHelper } from "@app/hooks";
|
||||||
import { useGetProjectRoles, useGetWorkspaceUsers } from "@app/hooks/api";
|
import { useGetProjectRoles, useGetWorkspaceUsers } from "@app/hooks/api";
|
||||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||||
import { ProjectMembershipRole } from "@app/hooks/api/roles/types";
|
|
||||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2;
|
const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2;
|
||||||
const formatRoleName = (role: string, customRoleName?: string) => {
|
|
||||||
if (role === ProjectMembershipRole.Custom) return customRoleName;
|
|
||||||
if (role === ProjectMembershipRole.Member) return "Developer";
|
|
||||||
if (role === ProjectMembershipRole.NoAccess) return "No access";
|
|
||||||
return role;
|
|
||||||
};
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
handlePopUpOpen: (
|
handlePopUpOpen: (
|
||||||
@@ -343,7 +337,7 @@ export const MembersTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
<Tag key={id}>
|
<Tag key={id}>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<div className="capitalize">
|
<div className="capitalize">
|
||||||
{formatRoleName(role, customRoleName)}
|
{formatProjectRoleName(role, customRoleName)}
|
||||||
</div>
|
</div>
|
||||||
{isTemporary && (
|
{isTemporary && (
|
||||||
<div>
|
<div>
|
||||||
@@ -386,7 +380,7 @@ export const MembersTable = ({ handlePopUpOpen }: Props) => {
|
|||||||
return (
|
return (
|
||||||
<Tag key={id} className="capitalize">
|
<Tag key={id} className="capitalize">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<div>{formatRoleName(role, customRoleName)}</div>
|
<div>{formatProjectRoleName(role, customRoleName)}</div>
|
||||||
{isTemporary && (
|
{isTemporary && (
|
||||||
<div>
|
<div>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import {
|
|||||||
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
||||||
import { usePopUp } from "@app/hooks";
|
import { usePopUp } from "@app/hooks";
|
||||||
import { useDeleteProjectRole, useGetProjectRoles } from "@app/hooks/api";
|
import { useDeleteProjectRole, useGetProjectRoles } from "@app/hooks/api";
|
||||||
import { TProjectRole } from "@app/hooks/api/roles/types";
|
import { ProjectMembershipRole, TProjectRole } from "@app/hooks/api/roles/types";
|
||||||
import { RoleModal } from "@app/pages/project/RoleDetailsBySlugPage/components/RoleModal";
|
import { RoleModal } from "@app/pages/project/RoleDetailsBySlugPage/components/RoleModal";
|
||||||
|
|
||||||
export const ProjectRoleList = () => {
|
export const ProjectRoleList = () => {
|
||||||
@@ -86,7 +86,9 @@ export const ProjectRoleList = () => {
|
|||||||
{isRolesLoading && <TableSkeleton columns={4} innerKey="org-roles" />}
|
{isRolesLoading && <TableSkeleton columns={4} innerKey="org-roles" />}
|
||||||
{roles?.map((role) => {
|
{roles?.map((role) => {
|
||||||
const { id, name, slug } = role;
|
const { id, name, slug } = role;
|
||||||
const isNonMutatable = ["admin", "member", "viewer", "no-access"].includes(slug);
|
const isNonMutatable = Object.values(ProjectMembershipRole).includes(
|
||||||
|
slug as ProjectMembershipRole
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tr
|
<Tr
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ import {
|
|||||||
isConditionalSubjects,
|
isConditionalSubjects,
|
||||||
PROJECT_PERMISSION_OBJECT,
|
PROJECT_PERMISSION_OBJECT,
|
||||||
projectRoleFormSchema,
|
projectRoleFormSchema,
|
||||||
|
ProjectTypePermissionSubjects,
|
||||||
rolePermission2Form
|
rolePermission2Form
|
||||||
} from "@app/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils";
|
} from "@app/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils";
|
||||||
import { renderConditionalComponents } from "@app/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection";
|
import { renderConditionalComponents } from "@app/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection";
|
||||||
@@ -269,6 +270,12 @@ export const IdentityProjectAdditionalPrivilegeModifySection = ({
|
|||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent className="thin-scrollbar max-h-96" align="end">
|
<DropdownMenuContent className="thin-scrollbar max-h-96" align="end">
|
||||||
{Object.keys(PROJECT_PERMISSION_OBJECT)
|
{Object.keys(PROJECT_PERMISSION_OBJECT)
|
||||||
|
.filter(
|
||||||
|
(sub) =>
|
||||||
|
ProjectTypePermissionSubjects[currentWorkspace.type][
|
||||||
|
sub as ProjectPermissionSub
|
||||||
|
]
|
||||||
|
)
|
||||||
.sort((a, b) =>
|
.sort((a, b) =>
|
||||||
PROJECT_PERMISSION_OBJECT[a as keyof typeof PROJECT_PERMISSION_OBJECT].title
|
PROJECT_PERMISSION_OBJECT[a as keyof typeof PROJECT_PERMISSION_OBJECT].title
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import {
|
|||||||
isConditionalSubjects,
|
isConditionalSubjects,
|
||||||
PROJECT_PERMISSION_OBJECT,
|
PROJECT_PERMISSION_OBJECT,
|
||||||
projectRoleFormSchema,
|
projectRoleFormSchema,
|
||||||
|
ProjectTypePermissionSubjects,
|
||||||
rolePermission2Form
|
rolePermission2Form
|
||||||
} from "@app/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils";
|
} from "@app/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils";
|
||||||
import { renderConditionalComponents } from "@app/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection";
|
import { renderConditionalComponents } from "@app/pages/project/RoleDetailsBySlugPage/components/RolePermissionsSection";
|
||||||
@@ -265,6 +266,12 @@ export const MembershipProjectAdditionalPrivilegeModifySection = ({
|
|||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent className="thin-scrollbar max-h-96" align="end">
|
<DropdownMenuContent className="thin-scrollbar max-h-96" align="end">
|
||||||
{Object.keys(PROJECT_PERMISSION_OBJECT)
|
{Object.keys(PROJECT_PERMISSION_OBJECT)
|
||||||
|
.filter(
|
||||||
|
(subject) =>
|
||||||
|
ProjectTypePermissionSubjects[currentWorkspace.type][
|
||||||
|
subject as ProjectPermissionSub
|
||||||
|
]
|
||||||
|
)
|
||||||
.sort((a, b) =>
|
.sort((a, b) =>
|
||||||
PROJECT_PERMISSION_OBJECT[a as keyof typeof PROJECT_PERMISSION_OBJECT].title
|
PROJECT_PERMISSION_OBJECT[a as keyof typeof PROJECT_PERMISSION_OBJECT].title
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
||||||
import { useDeleteProjectRole, useGetProjectRoleBySlug } from "@app/hooks/api";
|
import { useDeleteProjectRole, useGetProjectRoleBySlug } from "@app/hooks/api";
|
||||||
|
import { ProjectMembershipRole } from "@app/hooks/api/roles/types";
|
||||||
import { usePopUp } from "@app/hooks/usePopUp";
|
import { usePopUp } from "@app/hooks/usePopUp";
|
||||||
import { ProjectAccessControlTabs } from "@app/types/project";
|
import { ProjectAccessControlTabs } from "@app/types/project";
|
||||||
|
|
||||||
@@ -77,7 +78,9 @@ const Page = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isCustomRole = !["admin", "member", "viewer", "no-access"].includes(data?.slug ?? "");
|
const isCustomRole = !Object.values(ProjectMembershipRole).includes(
|
||||||
|
(data?.slug ?? "") as ProjectMembershipRole
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
|
||||||
|
|||||||
@@ -12,11 +12,14 @@ import {
|
|||||||
SelectItem
|
SelectItem
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { ProjectPermissionSub } from "@app/context";
|
import { ProjectPermissionSub } from "@app/context";
|
||||||
|
import { useGetProjectTypeFromRoute } from "@app/hooks";
|
||||||
|
import { ProjectType } from "@app/hooks/api/workspace/types";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
isConditionalSubjects,
|
isConditionalSubjects,
|
||||||
PROJECT_PERMISSION_OBJECT,
|
PROJECT_PERMISSION_OBJECT,
|
||||||
projectRoleFormSchema,
|
projectRoleFormSchema,
|
||||||
|
ProjectTypePermissionSubjects,
|
||||||
TFormSchema
|
TFormSchema
|
||||||
} from "./ProjectRoleModifySection.utils";
|
} from "./ProjectRoleModifySection.utils";
|
||||||
|
|
||||||
@@ -37,18 +40,20 @@ export const NewPermissionRule = ({ onClose }: Props) => {
|
|||||||
.extend({ type: z.nativeEnum(ProjectPermissionSub) })
|
.extend({ type: z.nativeEnum(ProjectPermissionSub) })
|
||||||
),
|
),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
type: ProjectPermissionSub.Secrets
|
type: ProjectPermissionSub.Project
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectedSubject = form.watch("type");
|
const selectedSubject = form.watch("type");
|
||||||
|
|
||||||
|
const projectType = useGetProjectTypeFromRoute();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Controller
|
<Controller
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="type"
|
name="type"
|
||||||
defaultValue={ProjectPermissionSub.Secrets}
|
defaultValue={ProjectPermissionSub.Project}
|
||||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||||
<FormControl label="Subject" errorText={error?.message} isError={Boolean(error)}>
|
<FormControl label="Subject" errorText={error?.message} isError={Boolean(error)}>
|
||||||
<Select
|
<Select
|
||||||
@@ -57,11 +62,18 @@ export const NewPermissionRule = ({ onClose }: Props) => {
|
|||||||
onValueChange={(e) => onChange(e)}
|
onValueChange={(e) => onChange(e)}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
>
|
>
|
||||||
{Object.keys(PROJECT_PERMISSION_OBJECT).map((subject) => (
|
{Object.keys(PROJECT_PERMISSION_OBJECT)
|
||||||
<SelectItem value={subject} key={`permission-create-${subject}`}>
|
.filter(
|
||||||
{PROJECT_PERMISSION_OBJECT[subject as ProjectPermissionSub].title}
|
(subject) =>
|
||||||
</SelectItem>
|
ProjectTypePermissionSubjects[projectType ?? ProjectType.SecretManager][
|
||||||
))}
|
subject as ProjectPermissionSub
|
||||||
|
]
|
||||||
|
)
|
||||||
|
.map((subject) => (
|
||||||
|
<SelectItem value={subject} key={`permission-create-${subject}`}>
|
||||||
|
{PROJECT_PERMISSION_OBJECT[subject as ProjectPermissionSub].title}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
TPermissionConditionOperators
|
TPermissionConditionOperators
|
||||||
} from "@app/context/ProjectPermissionContext/types";
|
} from "@app/context/ProjectPermissionContext/types";
|
||||||
import { TProjectPermission } from "@app/hooks/api/roles/types";
|
import { TProjectPermission } from "@app/hooks/api/roles/types";
|
||||||
|
import { ProjectType } from "@app/hooks/api/workspace/types";
|
||||||
|
|
||||||
const GeneralPolicyActionSchema = z.object({
|
const GeneralPolicyActionSchema = z.object({
|
||||||
read: z.boolean().optional(),
|
read: z.boolean().optional(),
|
||||||
@@ -1122,7 +1123,7 @@ export const PROJECT_PERMISSION_OBJECT: TProjectPermissionObject = {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
[ProjectPermissionSub.SecretApproval]: {
|
[ProjectPermissionSub.SecretApproval]: {
|
||||||
title: "Secret Protect policy",
|
title: "Secret Approval Policies",
|
||||||
actions: [
|
actions: [
|
||||||
{ label: "Read", value: "read" },
|
{ label: "Read", value: "read" },
|
||||||
{ label: "Create", value: "create" },
|
{ label: "Create", value: "create" },
|
||||||
@@ -1195,3 +1196,87 @@ export const PROJECT_PERMISSION_OBJECT: TProjectPermissionObject = {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const SharedPermissionSubjects = {
|
||||||
|
[ProjectPermissionSub.AuditLogs]: true,
|
||||||
|
[ProjectPermissionSub.Groups]: true,
|
||||||
|
[ProjectPermissionSub.Member]: true,
|
||||||
|
[ProjectPermissionSub.Identity]: true,
|
||||||
|
[ProjectPermissionSub.Project]: true,
|
||||||
|
[ProjectPermissionSub.Role]: true,
|
||||||
|
[ProjectPermissionSub.Settings]: true
|
||||||
|
};
|
||||||
|
|
||||||
|
const SecretsManagerPermissionSubjects = (enabled = false) => ({
|
||||||
|
[ProjectPermissionSub.SecretFolders]: enabled,
|
||||||
|
[ProjectPermissionSub.SecretImports]: enabled,
|
||||||
|
[ProjectPermissionSub.DynamicSecrets]: enabled,
|
||||||
|
[ProjectPermissionSub.Secrets]: enabled,
|
||||||
|
[ProjectPermissionSub.SecretApproval]: enabled,
|
||||||
|
[ProjectPermissionSub.Integrations]: enabled,
|
||||||
|
[ProjectPermissionSub.SecretSyncs]: enabled,
|
||||||
|
[ProjectPermissionSub.Kms]: enabled,
|
||||||
|
[ProjectPermissionSub.Environments]: enabled,
|
||||||
|
[ProjectPermissionSub.Tags]: enabled,
|
||||||
|
[ProjectPermissionSub.Webhooks]: enabled,
|
||||||
|
[ProjectPermissionSub.IpAllowList]: enabled,
|
||||||
|
[ProjectPermissionSub.SecretRollback]: enabled,
|
||||||
|
[ProjectPermissionSub.SecretRotation]: enabled,
|
||||||
|
[ProjectPermissionSub.ServiceTokens]: enabled
|
||||||
|
});
|
||||||
|
|
||||||
|
const KmsPermissionSubjects = (enabled = false) => ({
|
||||||
|
[ProjectPermissionSub.Cmek]: enabled,
|
||||||
|
[ProjectPermissionSub.Kmip]: enabled
|
||||||
|
});
|
||||||
|
|
||||||
|
const CertificateManagerPermissionSubjects = (enabled = false) => ({
|
||||||
|
[ProjectPermissionSub.PkiCollections]: enabled,
|
||||||
|
[ProjectPermissionSub.PkiAlerts]: enabled,
|
||||||
|
[ProjectPermissionSub.CertificateAuthorities]: enabled,
|
||||||
|
[ProjectPermissionSub.CertificateTemplates]: enabled,
|
||||||
|
[ProjectPermissionSub.Certificates]: enabled
|
||||||
|
});
|
||||||
|
|
||||||
|
const SshPermissionSubjects = (enabled = false) => ({
|
||||||
|
[ProjectPermissionSub.SshCertificateAuthorities]: enabled,
|
||||||
|
[ProjectPermissionSub.SshCertificates]: enabled,
|
||||||
|
[ProjectPermissionSub.SshCertificateTemplates]: enabled,
|
||||||
|
[ProjectPermissionSub.SshHosts]: enabled,
|
||||||
|
[ProjectPermissionSub.SshHostGroups]: enabled
|
||||||
|
});
|
||||||
|
|
||||||
|
// scott: this structure ensures we don't forget to add project permissions to their relevant project type
|
||||||
|
export const ProjectTypePermissionSubjects: Record<
|
||||||
|
ProjectType,
|
||||||
|
Record<ProjectPermissionSub, boolean>
|
||||||
|
> = {
|
||||||
|
[ProjectType.SecretManager]: {
|
||||||
|
...SharedPermissionSubjects,
|
||||||
|
...SecretsManagerPermissionSubjects(true),
|
||||||
|
...KmsPermissionSubjects(),
|
||||||
|
...CertificateManagerPermissionSubjects(),
|
||||||
|
...SshPermissionSubjects()
|
||||||
|
},
|
||||||
|
[ProjectType.KMS]: {
|
||||||
|
...SharedPermissionSubjects,
|
||||||
|
...KmsPermissionSubjects(true),
|
||||||
|
...SecretsManagerPermissionSubjects(),
|
||||||
|
...CertificateManagerPermissionSubjects(),
|
||||||
|
...SshPermissionSubjects()
|
||||||
|
},
|
||||||
|
[ProjectType.CertificateManager]: {
|
||||||
|
...SharedPermissionSubjects,
|
||||||
|
...CertificateManagerPermissionSubjects(true),
|
||||||
|
...KmsPermissionSubjects(),
|
||||||
|
...SecretsManagerPermissionSubjects(),
|
||||||
|
...SshPermissionSubjects()
|
||||||
|
},
|
||||||
|
[ProjectType.SSH]: {
|
||||||
|
...SharedPermissionSubjects,
|
||||||
|
...SshPermissionSubjects(true),
|
||||||
|
...CertificateManagerPermissionSubjects(),
|
||||||
|
...KmsPermissionSubjects(),
|
||||||
|
...SecretsManagerPermissionSubjects()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { IconButton, Tooltip } from "@app/components/v2";
|
|||||||
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
||||||
import { useTimedReset } from "@app/hooks";
|
import { useTimedReset } from "@app/hooks";
|
||||||
import { useGetProjectRoleBySlug } from "@app/hooks/api";
|
import { useGetProjectRoleBySlug } from "@app/hooks/api";
|
||||||
|
import { ProjectMembershipRole } from "@app/hooks/api/roles/types";
|
||||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -21,7 +22,9 @@ export const RoleDetailsSection = ({ roleSlug, handlePopUpOpen }: Props) => {
|
|||||||
const { currentWorkspace } = useWorkspace();
|
const { currentWorkspace } = useWorkspace();
|
||||||
const { data } = useGetProjectRoleBySlug(currentWorkspace?.id ?? "", roleSlug as string);
|
const { data } = useGetProjectRoleBySlug(currentWorkspace?.id ?? "", roleSlug as string);
|
||||||
|
|
||||||
const isCustomRole = !["admin", "member", "viewer", "no-access"].includes(data?.slug ?? "");
|
const isCustomRole = !Object.values(ProjectMembershipRole).includes(
|
||||||
|
(data?.slug ?? "") as ProjectMembershipRole
|
||||||
|
);
|
||||||
|
|
||||||
return data ? (
|
return data ? (
|
||||||
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||||
|
|||||||
@@ -115,12 +115,8 @@ export const RoleModal = ({ popUp, handlePopUpToggle }: Props) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
} catch (err) {
|
} catch {
|
||||||
console.error(err);
|
const text = `Failed to ${popUp?.role?.data ? "update" : "create"} role`;
|
||||||
const error = err as any;
|
|
||||||
const text =
|
|
||||||
error?.response?.data?.message ??
|
|
||||||
`Failed to ${popUp?.role?.data ? "update" : "create"} role`;
|
|
||||||
|
|
||||||
createNotification({
|
createNotification({
|
||||||
text,
|
text,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { ProjectPermissionSub, useWorkspace } from "@app/context";
|
|||||||
import { ProjectPermissionSet } from "@app/context/ProjectPermissionContext";
|
import { ProjectPermissionSet } from "@app/context/ProjectPermissionContext";
|
||||||
import { evaluatePermissionsAbility } from "@app/helpers/permissions";
|
import { evaluatePermissionsAbility } from "@app/helpers/permissions";
|
||||||
import { useGetProjectRoleBySlug, useUpdateProjectRole } from "@app/hooks/api";
|
import { useGetProjectRoleBySlug, useUpdateProjectRole } from "@app/hooks/api";
|
||||||
|
import { ProjectMembershipRole } from "@app/hooks/api/roles/types";
|
||||||
import { ProjectType } from "@app/hooks/api/workspace/types";
|
import { ProjectType } from "@app/hooks/api/workspace/types";
|
||||||
|
|
||||||
import { DynamicSecretPermissionConditions } from "./DynamicSecretPermissionConditions";
|
import { DynamicSecretPermissionConditions } from "./DynamicSecretPermissionConditions";
|
||||||
@@ -31,6 +32,7 @@ import {
|
|||||||
isConditionalSubjects,
|
isConditionalSubjects,
|
||||||
PROJECT_PERMISSION_OBJECT,
|
PROJECT_PERMISSION_OBJECT,
|
||||||
projectRoleFormSchema,
|
projectRoleFormSchema,
|
||||||
|
ProjectTypePermissionSubjects,
|
||||||
rolePermission2Form,
|
rolePermission2Form,
|
||||||
TFormSchema
|
TFormSchema
|
||||||
} from "./ProjectRoleModifySection.utils";
|
} from "./ProjectRoleModifySection.utils";
|
||||||
@@ -104,7 +106,9 @@ export const RolePermissionsSection = ({ roleSlug, isDisabled }: Props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isCustomRole = !["admin", "member", "viewer", "no-access"].includes(role?.slug ?? "");
|
const isCustomRole = !Object.values(ProjectMembershipRole).includes(
|
||||||
|
(role?.slug ?? "") as ProjectMembershipRole
|
||||||
|
);
|
||||||
|
|
||||||
const onNewPolicy = (selectedSubject: ProjectPermissionSub) => {
|
const onNewPolicy = (selectedSubject: ProjectPermissionSub) => {
|
||||||
const rootPolicyValue = form.getValues(`permissions.${selectedSubject}`);
|
const rootPolicyValue = form.getValues(`permissions.${selectedSubject}`);
|
||||||
@@ -192,6 +196,12 @@ export const RolePermissionsSection = ({ roleSlug, isDisabled }: Props) => {
|
|||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent className="thin-scrollbar max-h-96" align="end">
|
<DropdownMenuContent className="thin-scrollbar max-h-96" align="end">
|
||||||
{Object.keys(PROJECT_PERMISSION_OBJECT)
|
{Object.keys(PROJECT_PERMISSION_OBJECT)
|
||||||
|
.filter(
|
||||||
|
(subject) =>
|
||||||
|
ProjectTypePermissionSubjects[currentWorkspace.type][
|
||||||
|
subject as ProjectPermissionSub
|
||||||
|
]
|
||||||
|
)
|
||||||
.sort((a, b) =>
|
.sort((a, b) =>
|
||||||
PROJECT_PERMISSION_OBJECT[
|
PROJECT_PERMISSION_OBJECT[
|
||||||
a as keyof typeof PROJECT_PERMISSION_OBJECT
|
a as keyof typeof PROJECT_PERMISSION_OBJECT
|
||||||
@@ -221,17 +231,19 @@ export const RolePermissionsSection = ({ roleSlug, isDisabled }: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="py-4">
|
<div className="py-4">
|
||||||
{!isPending && <PermissionEmptyState />}
|
{!isPending && <PermissionEmptyState />}
|
||||||
{(Object.keys(PROJECT_PERMISSION_OBJECT) as ProjectPermissionSub[]).map((subject) => (
|
{(Object.keys(PROJECT_PERMISSION_OBJECT) as ProjectPermissionSub[])
|
||||||
<GeneralPermissionPolicies
|
.filter((subject) => ProjectTypePermissionSubjects[currentWorkspace.type][subject])
|
||||||
subject={subject}
|
.map((subject) => (
|
||||||
actions={PROJECT_PERMISSION_OBJECT[subject].actions}
|
<GeneralPermissionPolicies
|
||||||
title={PROJECT_PERMISSION_OBJECT[subject].title}
|
subject={subject}
|
||||||
key={`project-permission-${subject}`}
|
actions={PROJECT_PERMISSION_OBJECT[subject].actions}
|
||||||
isDisabled={isDisabled}
|
title={PROJECT_PERMISSION_OBJECT[subject].title}
|
||||||
>
|
key={`project-permission-${subject}`}
|
||||||
{renderConditionalComponents(subject, isDisabled)}
|
isDisabled={isDisabled}
|
||||||
</GeneralPermissionPolicies>
|
>
|
||||||
))}
|
{renderConditionalComponents(subject, isDisabled)}
|
||||||
|
</GeneralPermissionPolicies>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -52,14 +52,18 @@ import { Route as sshLayoutImport } from './pages/ssh/layout'
|
|||||||
import { Route as secretManagerLayoutImport } from './pages/secret-manager/layout'
|
import { Route as secretManagerLayoutImport } from './pages/secret-manager/layout'
|
||||||
import { Route as kmsLayoutImport } from './pages/kms/layout'
|
import { Route as kmsLayoutImport } from './pages/kms/layout'
|
||||||
import { Route as certManagerLayoutImport } from './pages/cert-manager/layout'
|
import { Route as certManagerLayoutImport } from './pages/cert-manager/layout'
|
||||||
|
import { Route as organizationSshSettingsPageRouteImport } from './pages/organization/SshSettingsPage/route'
|
||||||
import { Route as organizationSshOverviewPageRouteImport } from './pages/organization/SshOverviewPage/route'
|
import { Route as organizationSshOverviewPageRouteImport } from './pages/organization/SshOverviewPage/route'
|
||||||
import { Route as organizationSecretSharingSettingsPageRouteImport } from './pages/organization/SecretSharingSettingsPage/route'
|
import { Route as organizationSecretSharingSettingsPageRouteImport } from './pages/organization/SecretSharingSettingsPage/route'
|
||||||
|
import { Route as organizationSecretManagerSettingsPageRouteImport } from './pages/organization/SecretManagerSettingsPage/route'
|
||||||
import { Route as organizationSecretManagerOverviewPageRouteImport } from './pages/organization/SecretManagerOverviewPage/route'
|
import { Route as organizationSecretManagerOverviewPageRouteImport } from './pages/organization/SecretManagerOverviewPage/route'
|
||||||
import { Route as organizationRoleByIDPageRouteImport } from './pages/organization/RoleByIDPage/route'
|
import { Route as organizationRoleByIDPageRouteImport } from './pages/organization/RoleByIDPage/route'
|
||||||
import { Route as organizationUserDetailsByIDPageRouteImport } from './pages/organization/UserDetailsByIDPage/route'
|
import { Route as organizationUserDetailsByIDPageRouteImport } from './pages/organization/UserDetailsByIDPage/route'
|
||||||
|
import { Route as organizationKmsSettingsPageRouteImport } from './pages/organization/KmsSettingsPage/route'
|
||||||
import { Route as organizationKmsOverviewPageRouteImport } from './pages/organization/KmsOverviewPage/route'
|
import { Route as organizationKmsOverviewPageRouteImport } from './pages/organization/KmsOverviewPage/route'
|
||||||
import { Route as organizationIdentityDetailsByIDPageRouteImport } from './pages/organization/IdentityDetailsByIDPage/route'
|
import { Route as organizationIdentityDetailsByIDPageRouteImport } from './pages/organization/IdentityDetailsByIDPage/route'
|
||||||
import { Route as organizationGroupDetailsByIDPageRouteImport } from './pages/organization/GroupDetailsByIDPage/route'
|
import { Route as organizationGroupDetailsByIDPageRouteImport } from './pages/organization/GroupDetailsByIDPage/route'
|
||||||
|
import { Route as organizationCertManagerSettingsPageRouteImport } from './pages/organization/CertManagerSettingsPage/route'
|
||||||
import { Route as organizationCertManagerOverviewPageRouteImport } from './pages/organization/CertManagerOverviewPage/route'
|
import { Route as organizationCertManagerOverviewPageRouteImport } from './pages/organization/CertManagerOverviewPage/route'
|
||||||
import { Route as organizationSettingsPageRouteImport } from './pages/organization/SettingsPage/route'
|
import { Route as organizationSettingsPageRouteImport } from './pages/organization/SettingsPage/route'
|
||||||
import { Route as organizationSecretSharingPageRouteImport } from './pages/organization/SecretSharingPage/route'
|
import { Route as organizationSecretSharingPageRouteImport } from './pages/organization/SecretSharingPage/route'
|
||||||
@@ -604,6 +608,14 @@ const certManagerLayoutRoute = certManagerLayoutImport.update({
|
|||||||
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdRoute,
|
AuthenticateInjectOrgDetailsOrgLayoutCertManagerProjectIdRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
const organizationSshSettingsPageRouteRoute =
|
||||||
|
organizationSshSettingsPageRouteImport.update({
|
||||||
|
id: '/ssh/settings',
|
||||||
|
path: '/ssh/settings',
|
||||||
|
getParentRoute: () =>
|
||||||
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
const organizationSshOverviewPageRouteRoute =
|
const organizationSshOverviewPageRouteRoute =
|
||||||
organizationSshOverviewPageRouteImport.update({
|
organizationSshOverviewPageRouteImport.update({
|
||||||
id: '/ssh/overview',
|
id: '/ssh/overview',
|
||||||
@@ -620,6 +632,14 @@ const organizationSecretSharingSettingsPageRouteRoute =
|
|||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute,
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
const organizationSecretManagerSettingsPageRouteRoute =
|
||||||
|
organizationSecretManagerSettingsPageRouteImport.update({
|
||||||
|
id: '/secret-manager/settings',
|
||||||
|
path: '/secret-manager/settings',
|
||||||
|
getParentRoute: () =>
|
||||||
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
const organizationSecretManagerOverviewPageRouteRoute =
|
const organizationSecretManagerOverviewPageRouteRoute =
|
||||||
organizationSecretManagerOverviewPageRouteImport.update({
|
organizationSecretManagerOverviewPageRouteImport.update({
|
||||||
id: '/secret-manager/overview',
|
id: '/secret-manager/overview',
|
||||||
@@ -644,6 +664,14 @@ const organizationUserDetailsByIDPageRouteRoute =
|
|||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
const organizationKmsSettingsPageRouteRoute =
|
||||||
|
organizationKmsSettingsPageRouteImport.update({
|
||||||
|
id: '/kms/settings',
|
||||||
|
path: '/kms/settings',
|
||||||
|
getParentRoute: () =>
|
||||||
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
const organizationKmsOverviewPageRouteRoute =
|
const organizationKmsOverviewPageRouteRoute =
|
||||||
organizationKmsOverviewPageRouteImport.update({
|
organizationKmsOverviewPageRouteImport.update({
|
||||||
id: '/kms/overview',
|
id: '/kms/overview',
|
||||||
@@ -668,6 +696,14 @@ const organizationGroupDetailsByIDPageRouteRoute =
|
|||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
const organizationCertManagerSettingsPageRouteRoute =
|
||||||
|
organizationCertManagerSettingsPageRouteImport.update({
|
||||||
|
id: '/cert-manager/settings',
|
||||||
|
path: '/cert-manager/settings',
|
||||||
|
getParentRoute: () =>
|
||||||
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
const organizationCertManagerOverviewPageRouteRoute =
|
const organizationCertManagerOverviewPageRouteRoute =
|
||||||
organizationCertManagerOverviewPageRouteImport.update({
|
organizationCertManagerOverviewPageRouteImport.update({
|
||||||
id: '/cert-manager/overview',
|
id: '/cert-manager/overview',
|
||||||
@@ -2072,6 +2108,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof organizationCertManagerOverviewPageRouteImport
|
preLoaderRoute: typeof organizationCertManagerOverviewPageRouteImport
|
||||||
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
||||||
}
|
}
|
||||||
|
'/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/settings': {
|
||||||
|
id: '/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/settings'
|
||||||
|
path: '/cert-manager/settings'
|
||||||
|
fullPath: '/organization/cert-manager/settings'
|
||||||
|
preLoaderRoute: typeof organizationCertManagerSettingsPageRouteImport
|
||||||
|
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
||||||
|
}
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId': {
|
'/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId': {
|
||||||
id: '/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId'
|
id: '/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId'
|
||||||
path: '/groups/$groupId'
|
path: '/groups/$groupId'
|
||||||
@@ -2093,6 +2136,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof organizationKmsOverviewPageRouteImport
|
preLoaderRoute: typeof organizationKmsOverviewPageRouteImport
|
||||||
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
||||||
}
|
}
|
||||||
|
'/_authenticate/_inject-org-details/_org-layout/organization/kms/settings': {
|
||||||
|
id: '/_authenticate/_inject-org-details/_org-layout/organization/kms/settings'
|
||||||
|
path: '/kms/settings'
|
||||||
|
fullPath: '/organization/kms/settings'
|
||||||
|
preLoaderRoute: typeof organizationKmsSettingsPageRouteImport
|
||||||
|
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
||||||
|
}
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/members/$membershipId': {
|
'/_authenticate/_inject-org-details/_org-layout/organization/members/$membershipId': {
|
||||||
id: '/_authenticate/_inject-org-details/_org-layout/organization/members/$membershipId'
|
id: '/_authenticate/_inject-org-details/_org-layout/organization/members/$membershipId'
|
||||||
path: '/members/$membershipId'
|
path: '/members/$membershipId'
|
||||||
@@ -2114,6 +2164,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof organizationSecretManagerOverviewPageRouteImport
|
preLoaderRoute: typeof organizationSecretManagerOverviewPageRouteImport
|
||||||
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
||||||
}
|
}
|
||||||
|
'/_authenticate/_inject-org-details/_org-layout/organization/secret-manager/settings': {
|
||||||
|
id: '/_authenticate/_inject-org-details/_org-layout/organization/secret-manager/settings'
|
||||||
|
path: '/secret-manager/settings'
|
||||||
|
fullPath: '/organization/secret-manager/settings'
|
||||||
|
preLoaderRoute: typeof organizationSecretManagerSettingsPageRouteImport
|
||||||
|
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
||||||
|
}
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/settings': {
|
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/settings': {
|
||||||
id: '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/settings'
|
id: '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/settings'
|
||||||
path: '/settings'
|
path: '/settings'
|
||||||
@@ -2128,6 +2185,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof organizationSshOverviewPageRouteImport
|
preLoaderRoute: typeof organizationSshOverviewPageRouteImport
|
||||||
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
||||||
}
|
}
|
||||||
|
'/_authenticate/_inject-org-details/_org-layout/organization/ssh/settings': {
|
||||||
|
id: '/_authenticate/_inject-org-details/_org-layout/organization/ssh/settings'
|
||||||
|
path: '/ssh/settings'
|
||||||
|
fullPath: '/organization/ssh/settings'
|
||||||
|
preLoaderRoute: typeof organizationSshSettingsPageRouteImport
|
||||||
|
parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport
|
||||||
|
}
|
||||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout': {
|
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout': {
|
||||||
id: '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout'
|
id: '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout'
|
||||||
path: ''
|
path: ''
|
||||||
@@ -3168,13 +3232,17 @@ interface AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren {
|
|||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren
|
||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRouteWithChildren
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRouteWithChildren
|
||||||
organizationCertManagerOverviewPageRouteRoute: typeof organizationCertManagerOverviewPageRouteRoute
|
organizationCertManagerOverviewPageRouteRoute: typeof organizationCertManagerOverviewPageRouteRoute
|
||||||
|
organizationCertManagerSettingsPageRouteRoute: typeof organizationCertManagerSettingsPageRouteRoute
|
||||||
organizationGroupDetailsByIDPageRouteRoute: typeof organizationGroupDetailsByIDPageRouteRoute
|
organizationGroupDetailsByIDPageRouteRoute: typeof organizationGroupDetailsByIDPageRouteRoute
|
||||||
organizationIdentityDetailsByIDPageRouteRoute: typeof organizationIdentityDetailsByIDPageRouteRoute
|
organizationIdentityDetailsByIDPageRouteRoute: typeof organizationIdentityDetailsByIDPageRouteRoute
|
||||||
organizationKmsOverviewPageRouteRoute: typeof organizationKmsOverviewPageRouteRoute
|
organizationKmsOverviewPageRouteRoute: typeof organizationKmsOverviewPageRouteRoute
|
||||||
|
organizationKmsSettingsPageRouteRoute: typeof organizationKmsSettingsPageRouteRoute
|
||||||
organizationUserDetailsByIDPageRouteRoute: typeof organizationUserDetailsByIDPageRouteRoute
|
organizationUserDetailsByIDPageRouteRoute: typeof organizationUserDetailsByIDPageRouteRoute
|
||||||
organizationRoleByIDPageRouteRoute: typeof organizationRoleByIDPageRouteRoute
|
organizationRoleByIDPageRouteRoute: typeof organizationRoleByIDPageRouteRoute
|
||||||
organizationSecretManagerOverviewPageRouteRoute: typeof organizationSecretManagerOverviewPageRouteRoute
|
organizationSecretManagerOverviewPageRouteRoute: typeof organizationSecretManagerOverviewPageRouteRoute
|
||||||
|
organizationSecretManagerSettingsPageRouteRoute: typeof organizationSecretManagerSettingsPageRouteRoute
|
||||||
organizationSshOverviewPageRouteRoute: typeof organizationSshOverviewPageRouteRoute
|
organizationSshOverviewPageRouteRoute: typeof organizationSshOverviewPageRouteRoute
|
||||||
|
organizationSshSettingsPageRouteRoute: typeof organizationSshSettingsPageRouteRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren: AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren =
|
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren: AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren =
|
||||||
@@ -3196,19 +3264,27 @@ const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren: Authentica
|
|||||||
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRouteWithChildren,
|
AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRouteWithChildren,
|
||||||
organizationCertManagerOverviewPageRouteRoute:
|
organizationCertManagerOverviewPageRouteRoute:
|
||||||
organizationCertManagerOverviewPageRouteRoute,
|
organizationCertManagerOverviewPageRouteRoute,
|
||||||
|
organizationCertManagerSettingsPageRouteRoute:
|
||||||
|
organizationCertManagerSettingsPageRouteRoute,
|
||||||
organizationGroupDetailsByIDPageRouteRoute:
|
organizationGroupDetailsByIDPageRouteRoute:
|
||||||
organizationGroupDetailsByIDPageRouteRoute,
|
organizationGroupDetailsByIDPageRouteRoute,
|
||||||
organizationIdentityDetailsByIDPageRouteRoute:
|
organizationIdentityDetailsByIDPageRouteRoute:
|
||||||
organizationIdentityDetailsByIDPageRouteRoute,
|
organizationIdentityDetailsByIDPageRouteRoute,
|
||||||
organizationKmsOverviewPageRouteRoute:
|
organizationKmsOverviewPageRouteRoute:
|
||||||
organizationKmsOverviewPageRouteRoute,
|
organizationKmsOverviewPageRouteRoute,
|
||||||
|
organizationKmsSettingsPageRouteRoute:
|
||||||
|
organizationKmsSettingsPageRouteRoute,
|
||||||
organizationUserDetailsByIDPageRouteRoute:
|
organizationUserDetailsByIDPageRouteRoute:
|
||||||
organizationUserDetailsByIDPageRouteRoute,
|
organizationUserDetailsByIDPageRouteRoute,
|
||||||
organizationRoleByIDPageRouteRoute: organizationRoleByIDPageRouteRoute,
|
organizationRoleByIDPageRouteRoute: organizationRoleByIDPageRouteRoute,
|
||||||
organizationSecretManagerOverviewPageRouteRoute:
|
organizationSecretManagerOverviewPageRouteRoute:
|
||||||
organizationSecretManagerOverviewPageRouteRoute,
|
organizationSecretManagerOverviewPageRouteRoute,
|
||||||
|
organizationSecretManagerSettingsPageRouteRoute:
|
||||||
|
organizationSecretManagerSettingsPageRouteRoute,
|
||||||
organizationSshOverviewPageRouteRoute:
|
organizationSshOverviewPageRouteRoute:
|
||||||
organizationSshOverviewPageRouteRoute,
|
organizationSshOverviewPageRouteRoute,
|
||||||
|
organizationSshSettingsPageRouteRoute:
|
||||||
|
organizationSshSettingsPageRouteRoute,
|
||||||
}
|
}
|
||||||
|
|
||||||
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteWithChildren =
|
const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteWithChildren =
|
||||||
@@ -3893,14 +3969,18 @@ export interface FileRoutesByFullPath {
|
|||||||
'/organization/secret-sharing/': typeof organizationSecretSharingPageRouteRoute
|
'/organization/secret-sharing/': typeof organizationSecretSharingPageRouteRoute
|
||||||
'/organization/settings/': typeof organizationSettingsPageRouteRoute
|
'/organization/settings/': typeof organizationSettingsPageRouteRoute
|
||||||
'/organization/cert-manager/overview': typeof organizationCertManagerOverviewPageRouteRoute
|
'/organization/cert-manager/overview': typeof organizationCertManagerOverviewPageRouteRoute
|
||||||
|
'/organization/cert-manager/settings': typeof organizationCertManagerSettingsPageRouteRoute
|
||||||
'/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
|
'/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
|
||||||
'/organization/identities/$identityId': typeof organizationIdentityDetailsByIDPageRouteRoute
|
'/organization/identities/$identityId': typeof organizationIdentityDetailsByIDPageRouteRoute
|
||||||
'/organization/kms/overview': typeof organizationKmsOverviewPageRouteRoute
|
'/organization/kms/overview': typeof organizationKmsOverviewPageRouteRoute
|
||||||
|
'/organization/kms/settings': typeof organizationKmsSettingsPageRouteRoute
|
||||||
'/organization/members/$membershipId': typeof organizationUserDetailsByIDPageRouteRoute
|
'/organization/members/$membershipId': typeof organizationUserDetailsByIDPageRouteRoute
|
||||||
'/organization/roles/$roleId': typeof organizationRoleByIDPageRouteRoute
|
'/organization/roles/$roleId': typeof organizationRoleByIDPageRouteRoute
|
||||||
'/organization/secret-manager/overview': typeof organizationSecretManagerOverviewPageRouteRoute
|
'/organization/secret-manager/overview': typeof organizationSecretManagerOverviewPageRouteRoute
|
||||||
|
'/organization/secret-manager/settings': typeof organizationSecretManagerSettingsPageRouteRoute
|
||||||
'/organization/secret-sharing/settings': typeof organizationSecretSharingSettingsPageRouteRoute
|
'/organization/secret-sharing/settings': typeof organizationSecretSharingSettingsPageRouteRoute
|
||||||
'/organization/ssh/overview': typeof organizationSshOverviewPageRouteRoute
|
'/organization/ssh/overview': typeof organizationSshOverviewPageRouteRoute
|
||||||
|
'/organization/ssh/settings': typeof organizationSshSettingsPageRouteRoute
|
||||||
'/cert-manager/$projectId/alerting': typeof certManagerAlertingPageRouteRoute
|
'/cert-manager/$projectId/alerting': typeof certManagerAlertingPageRouteRoute
|
||||||
'/cert-manager/$projectId/certificate-authorities': typeof certManagerCertificateAuthoritiesPageRouteRoute
|
'/cert-manager/$projectId/certificate-authorities': typeof certManagerCertificateAuthoritiesPageRouteRoute
|
||||||
'/cert-manager/$projectId/overview': typeof certManagerCertificatesPageRouteRoute
|
'/cert-manager/$projectId/overview': typeof certManagerCertificatesPageRouteRoute
|
||||||
@@ -4072,14 +4152,18 @@ export interface FileRoutesByTo {
|
|||||||
'/organization/secret-sharing': typeof organizationSecretSharingPageRouteRoute
|
'/organization/secret-sharing': typeof organizationSecretSharingPageRouteRoute
|
||||||
'/organization/settings': typeof organizationSettingsPageRouteRoute
|
'/organization/settings': typeof organizationSettingsPageRouteRoute
|
||||||
'/organization/cert-manager/overview': typeof organizationCertManagerOverviewPageRouteRoute
|
'/organization/cert-manager/overview': typeof organizationCertManagerOverviewPageRouteRoute
|
||||||
|
'/organization/cert-manager/settings': typeof organizationCertManagerSettingsPageRouteRoute
|
||||||
'/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
|
'/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
|
||||||
'/organization/identities/$identityId': typeof organizationIdentityDetailsByIDPageRouteRoute
|
'/organization/identities/$identityId': typeof organizationIdentityDetailsByIDPageRouteRoute
|
||||||
'/organization/kms/overview': typeof organizationKmsOverviewPageRouteRoute
|
'/organization/kms/overview': typeof organizationKmsOverviewPageRouteRoute
|
||||||
|
'/organization/kms/settings': typeof organizationKmsSettingsPageRouteRoute
|
||||||
'/organization/members/$membershipId': typeof organizationUserDetailsByIDPageRouteRoute
|
'/organization/members/$membershipId': typeof organizationUserDetailsByIDPageRouteRoute
|
||||||
'/organization/roles/$roleId': typeof organizationRoleByIDPageRouteRoute
|
'/organization/roles/$roleId': typeof organizationRoleByIDPageRouteRoute
|
||||||
'/organization/secret-manager/overview': typeof organizationSecretManagerOverviewPageRouteRoute
|
'/organization/secret-manager/overview': typeof organizationSecretManagerOverviewPageRouteRoute
|
||||||
|
'/organization/secret-manager/settings': typeof organizationSecretManagerSettingsPageRouteRoute
|
||||||
'/organization/secret-sharing/settings': typeof organizationSecretSharingSettingsPageRouteRoute
|
'/organization/secret-sharing/settings': typeof organizationSecretSharingSettingsPageRouteRoute
|
||||||
'/organization/ssh/overview': typeof organizationSshOverviewPageRouteRoute
|
'/organization/ssh/overview': typeof organizationSshOverviewPageRouteRoute
|
||||||
|
'/organization/ssh/settings': typeof organizationSshSettingsPageRouteRoute
|
||||||
'/cert-manager/$projectId/alerting': typeof certManagerAlertingPageRouteRoute
|
'/cert-manager/$projectId/alerting': typeof certManagerAlertingPageRouteRoute
|
||||||
'/cert-manager/$projectId/certificate-authorities': typeof certManagerCertificateAuthoritiesPageRouteRoute
|
'/cert-manager/$projectId/certificate-authorities': typeof certManagerCertificateAuthoritiesPageRouteRoute
|
||||||
'/cert-manager/$projectId/overview': typeof certManagerCertificatesPageRouteRoute
|
'/cert-manager/$projectId/overview': typeof certManagerCertificatesPageRouteRoute
|
||||||
@@ -4264,14 +4348,18 @@ export interface FileRoutesById {
|
|||||||
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/': typeof organizationSecretSharingPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/': typeof organizationSecretSharingPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/settings/': typeof organizationSettingsPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/settings/': typeof organizationSettingsPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/overview': typeof organizationCertManagerOverviewPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/overview': typeof organizationCertManagerOverviewPageRouteRoute
|
||||||
|
'/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/settings': typeof organizationCertManagerSettingsPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/identities/$identityId': typeof organizationIdentityDetailsByIDPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/identities/$identityId': typeof organizationIdentityDetailsByIDPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/kms/overview': typeof organizationKmsOverviewPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/kms/overview': typeof organizationKmsOverviewPageRouteRoute
|
||||||
|
'/_authenticate/_inject-org-details/_org-layout/organization/kms/settings': typeof organizationKmsSettingsPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/members/$membershipId': typeof organizationUserDetailsByIDPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/members/$membershipId': typeof organizationUserDetailsByIDPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/roles/$roleId': typeof organizationRoleByIDPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/roles/$roleId': typeof organizationRoleByIDPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/secret-manager/overview': typeof organizationSecretManagerOverviewPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/secret-manager/overview': typeof organizationSecretManagerOverviewPageRouteRoute
|
||||||
|
'/_authenticate/_inject-org-details/_org-layout/organization/secret-manager/settings': typeof organizationSecretManagerSettingsPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/settings': typeof organizationSecretSharingSettingsPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/settings': typeof organizationSecretSharingSettingsPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/ssh/overview': typeof organizationSshOverviewPageRouteRoute
|
'/_authenticate/_inject-org-details/_org-layout/organization/ssh/overview': typeof organizationSshOverviewPageRouteRoute
|
||||||
|
'/_authenticate/_inject-org-details/_org-layout/organization/ssh/settings': typeof organizationSshSettingsPageRouteRoute
|
||||||
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout': typeof certManagerLayoutRouteWithChildren
|
'/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout': typeof certManagerLayoutRouteWithChildren
|
||||||
'/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout': typeof kmsLayoutRouteWithChildren
|
'/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout': typeof kmsLayoutRouteWithChildren
|
||||||
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout': typeof secretManagerLayoutRouteWithChildren
|
'/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout': typeof secretManagerLayoutRouteWithChildren
|
||||||
@@ -4457,14 +4545,18 @@ export interface FileRouteTypes {
|
|||||||
| '/organization/secret-sharing/'
|
| '/organization/secret-sharing/'
|
||||||
| '/organization/settings/'
|
| '/organization/settings/'
|
||||||
| '/organization/cert-manager/overview'
|
| '/organization/cert-manager/overview'
|
||||||
|
| '/organization/cert-manager/settings'
|
||||||
| '/organization/groups/$groupId'
|
| '/organization/groups/$groupId'
|
||||||
| '/organization/identities/$identityId'
|
| '/organization/identities/$identityId'
|
||||||
| '/organization/kms/overview'
|
| '/organization/kms/overview'
|
||||||
|
| '/organization/kms/settings'
|
||||||
| '/organization/members/$membershipId'
|
| '/organization/members/$membershipId'
|
||||||
| '/organization/roles/$roleId'
|
| '/organization/roles/$roleId'
|
||||||
| '/organization/secret-manager/overview'
|
| '/organization/secret-manager/overview'
|
||||||
|
| '/organization/secret-manager/settings'
|
||||||
| '/organization/secret-sharing/settings'
|
| '/organization/secret-sharing/settings'
|
||||||
| '/organization/ssh/overview'
|
| '/organization/ssh/overview'
|
||||||
|
| '/organization/ssh/settings'
|
||||||
| '/cert-manager/$projectId/alerting'
|
| '/cert-manager/$projectId/alerting'
|
||||||
| '/cert-manager/$projectId/certificate-authorities'
|
| '/cert-manager/$projectId/certificate-authorities'
|
||||||
| '/cert-manager/$projectId/overview'
|
| '/cert-manager/$projectId/overview'
|
||||||
@@ -4635,14 +4727,18 @@ export interface FileRouteTypes {
|
|||||||
| '/organization/secret-sharing'
|
| '/organization/secret-sharing'
|
||||||
| '/organization/settings'
|
| '/organization/settings'
|
||||||
| '/organization/cert-manager/overview'
|
| '/organization/cert-manager/overview'
|
||||||
|
| '/organization/cert-manager/settings'
|
||||||
| '/organization/groups/$groupId'
|
| '/organization/groups/$groupId'
|
||||||
| '/organization/identities/$identityId'
|
| '/organization/identities/$identityId'
|
||||||
| '/organization/kms/overview'
|
| '/organization/kms/overview'
|
||||||
|
| '/organization/kms/settings'
|
||||||
| '/organization/members/$membershipId'
|
| '/organization/members/$membershipId'
|
||||||
| '/organization/roles/$roleId'
|
| '/organization/roles/$roleId'
|
||||||
| '/organization/secret-manager/overview'
|
| '/organization/secret-manager/overview'
|
||||||
|
| '/organization/secret-manager/settings'
|
||||||
| '/organization/secret-sharing/settings'
|
| '/organization/secret-sharing/settings'
|
||||||
| '/organization/ssh/overview'
|
| '/organization/ssh/overview'
|
||||||
|
| '/organization/ssh/settings'
|
||||||
| '/cert-manager/$projectId/alerting'
|
| '/cert-manager/$projectId/alerting'
|
||||||
| '/cert-manager/$projectId/certificate-authorities'
|
| '/cert-manager/$projectId/certificate-authorities'
|
||||||
| '/cert-manager/$projectId/overview'
|
| '/cert-manager/$projectId/overview'
|
||||||
@@ -4825,14 +4921,18 @@ export interface FileRouteTypes {
|
|||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/settings/'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/settings/'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/overview'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/overview'
|
||||||
|
| '/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/settings'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/identities/$identityId'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/identities/$identityId'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/kms/overview'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/kms/overview'
|
||||||
|
| '/_authenticate/_inject-org-details/_org-layout/organization/kms/settings'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/members/$membershipId'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/members/$membershipId'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/roles/$roleId'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/roles/$roleId'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/secret-manager/overview'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/secret-manager/overview'
|
||||||
|
| '/_authenticate/_inject-org-details/_org-layout/organization/secret-manager/settings'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/settings'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/settings'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/organization/ssh/overview'
|
| '/_authenticate/_inject-org-details/_org-layout/organization/ssh/overview'
|
||||||
|
| '/_authenticate/_inject-org-details/_org-layout/organization/ssh/settings'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout'
|
| '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout'
|
| '/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout'
|
||||||
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout'
|
| '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId/_secret-manager-layout'
|
||||||
@@ -5209,13 +5309,17 @@ export const routeTree = rootRoute
|
|||||||
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing",
|
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/settings",
|
"/_authenticate/_inject-org-details/_org-layout/organization/settings",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/overview",
|
"/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/overview",
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/settings",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId",
|
"/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/identities/$identityId",
|
"/_authenticate/_inject-org-details/_org-layout/organization/identities/$identityId",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/kms/overview",
|
"/_authenticate/_inject-org-details/_org-layout/organization/kms/overview",
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/kms/settings",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/members/$membershipId",
|
"/_authenticate/_inject-org-details/_org-layout/organization/members/$membershipId",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/roles/$roleId",
|
"/_authenticate/_inject-org-details/_org-layout/organization/roles/$roleId",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/secret-manager/overview",
|
"/_authenticate/_inject-org-details/_org-layout/organization/secret-manager/overview",
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/ssh/overview"
|
"/_authenticate/_inject-org-details/_org-layout/organization/secret-manager/settings",
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/ssh/overview",
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/ssh/settings"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"/_authenticate/_inject-org-details/admin/_admin-layout": {
|
"/_authenticate/_inject-org-details/admin/_admin-layout": {
|
||||||
@@ -5328,6 +5432,10 @@ export const routeTree = rootRoute
|
|||||||
"filePath": "organization/CertManagerOverviewPage/route.tsx",
|
"filePath": "organization/CertManagerOverviewPage/route.tsx",
|
||||||
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
||||||
},
|
},
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/cert-manager/settings": {
|
||||||
|
"filePath": "organization/CertManagerSettingsPage/route.tsx",
|
||||||
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
||||||
|
},
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId": {
|
"/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId": {
|
||||||
"filePath": "organization/GroupDetailsByIDPage/route.tsx",
|
"filePath": "organization/GroupDetailsByIDPage/route.tsx",
|
||||||
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
||||||
@@ -5340,6 +5448,10 @@ export const routeTree = rootRoute
|
|||||||
"filePath": "organization/KmsOverviewPage/route.tsx",
|
"filePath": "organization/KmsOverviewPage/route.tsx",
|
||||||
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
||||||
},
|
},
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/kms/settings": {
|
||||||
|
"filePath": "organization/KmsSettingsPage/route.tsx",
|
||||||
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
||||||
|
},
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/members/$membershipId": {
|
"/_authenticate/_inject-org-details/_org-layout/organization/members/$membershipId": {
|
||||||
"filePath": "organization/UserDetailsByIDPage/route.tsx",
|
"filePath": "organization/UserDetailsByIDPage/route.tsx",
|
||||||
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
||||||
@@ -5352,6 +5464,10 @@ export const routeTree = rootRoute
|
|||||||
"filePath": "organization/SecretManagerOverviewPage/route.tsx",
|
"filePath": "organization/SecretManagerOverviewPage/route.tsx",
|
||||||
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
||||||
},
|
},
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/secret-manager/settings": {
|
||||||
|
"filePath": "organization/SecretManagerSettingsPage/route.tsx",
|
||||||
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
||||||
|
},
|
||||||
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/settings": {
|
"/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/settings": {
|
||||||
"filePath": "organization/SecretSharingSettingsPage/route.tsx",
|
"filePath": "organization/SecretSharingSettingsPage/route.tsx",
|
||||||
"parent": "/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing"
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing"
|
||||||
@@ -5360,6 +5476,10 @@ export const routeTree = rootRoute
|
|||||||
"filePath": "organization/SshOverviewPage/route.tsx",
|
"filePath": "organization/SshOverviewPage/route.tsx",
|
||||||
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
||||||
},
|
},
|
||||||
|
"/_authenticate/_inject-org-details/_org-layout/organization/ssh/settings": {
|
||||||
|
"filePath": "organization/SshSettingsPage/route.tsx",
|
||||||
|
"parent": "/_authenticate/_inject-org-details/_org-layout/organization"
|
||||||
|
},
|
||||||
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout": {
|
"/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout": {
|
||||||
"filePath": "cert-manager/layout.tsx",
|
"filePath": "cert-manager/layout.tsx",
|
||||||
"parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId",
|
"parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId",
|
||||||
|
|||||||
@@ -9,9 +9,13 @@ const adminRoute = route("/admin", [
|
|||||||
|
|
||||||
const organizationRoutes = route("/organization", [
|
const organizationRoutes = route("/organization", [
|
||||||
route("/secret-manager/overview", "organization/SecretManagerOverviewPage/route.tsx"),
|
route("/secret-manager/overview", "organization/SecretManagerOverviewPage/route.tsx"),
|
||||||
|
route("/secret-manager/settings", "organization/SecretManagerSettingsPage/route.tsx"),
|
||||||
route("/cert-manager/overview", "organization/CertManagerOverviewPage/route.tsx"),
|
route("/cert-manager/overview", "organization/CertManagerOverviewPage/route.tsx"),
|
||||||
|
route("/cert-manager/settings", "organization/CertManagerSettingsPage/route.tsx"),
|
||||||
route("/ssh/overview", "organization/SshOverviewPage/route.tsx"),
|
route("/ssh/overview", "organization/SshOverviewPage/route.tsx"),
|
||||||
|
route("/ssh/settings", "organization/SshSettingsPage/route.tsx"),
|
||||||
route("/kms/overview", "organization/KmsOverviewPage/route.tsx"),
|
route("/kms/overview", "organization/KmsOverviewPage/route.tsx"),
|
||||||
|
route("/kms/settings", "organization/KmsSettingsPage/route.tsx"),
|
||||||
route("/access-management", "organization/AccessManagementPage/route.tsx"),
|
route("/access-management", "organization/AccessManagementPage/route.tsx"),
|
||||||
route("/admin", "organization/AdminPage/route.tsx"),
|
route("/admin", "organization/AdminPage/route.tsx"),
|
||||||
route("/audit-logs", "organization/AuditLogsPage/route.tsx"),
|
route("/audit-logs", "organization/AuditLogsPage/route.tsx"),
|
||||||
|
|||||||