diff --git a/backend/src/ee/routes/v1/dynamic-secret-lease-router.ts b/backend/src/ee/routes/v1/dynamic-secret-lease-router.ts index b75a2dae0..7c42c7f99 100644 --- a/backend/src/ee/routes/v1/dynamic-secret-lease-router.ts +++ b/backend/src/ee/routes/v1/dynamic-secret-lease-router.ts @@ -1,7 +1,7 @@ import { z } from "zod"; import { DynamicSecretLeasesSchema } from "@app/db/schemas"; -import { DYNAMIC_SECRET_LEASES } from "@app/lib/api-docs"; +import { ApiDocsTags, DYNAMIC_SECRET_LEASES } from "@app/lib/api-docs"; import { daysToMillisecond } from "@app/lib/dates"; import { removeTrailingSlash } from "@app/lib/fn"; import { ms } from "@app/lib/ms"; @@ -18,6 +18,8 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.DynamicSecrets], body: z.object({ dynamicSecretName: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.CREATE.dynamicSecretName).toLowerCase(), projectSlug: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.CREATE.projectSlug), @@ -65,6 +67,8 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.DynamicSecrets], params: z.object({ leaseId: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.DELETE.leaseId) }), @@ -107,6 +111,8 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.DynamicSecrets], params: z.object({ leaseId: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.RENEW.leaseId) }), @@ -160,6 +166,8 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.DynamicSecrets], params: z.object({ leaseId: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.GET_BY_LEASEID.leaseId) }), diff --git a/backend/src/ee/routes/v1/dynamic-secret-router.ts b/backend/src/ee/routes/v1/dynamic-secret-router.ts index fdaaf5932..6e70effe4 100644 --- a/backend/src/ee/routes/v1/dynamic-secret-router.ts +++ b/backend/src/ee/routes/v1/dynamic-secret-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { DynamicSecretLeasesSchema } from "@app/db/schemas"; import { DynamicSecretProviderSchema } from "@app/ee/services/dynamic-secret/providers/models"; -import { DYNAMIC_SECRETS } from "@app/lib/api-docs"; +import { ApiDocsTags, DYNAMIC_SECRETS } from "@app/lib/api-docs"; import { daysToMillisecond } from "@app/lib/dates"; import { removeTrailingSlash } from "@app/lib/fn"; import { ms } from "@app/lib/ms"; @@ -21,6 +21,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.DynamicSecrets], body: z.object({ projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.CREATE.projectSlug), provider: DynamicSecretProviderSchema.describe(DYNAMIC_SECRETS.CREATE.provider), @@ -111,6 +113,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.DynamicSecrets], params: z.object({ name: z.string().toLowerCase().describe(DYNAMIC_SECRETS.UPDATE.name) }), @@ -179,6 +183,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.DynamicSecrets], params: z.object({ name: z.string().toLowerCase().describe(DYNAMIC_SECRETS.DELETE.name) }), @@ -215,6 +221,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.DynamicSecrets], params: z.object({ name: z.string().min(1).describe(DYNAMIC_SECRETS.GET_BY_NAME.name) }), @@ -253,6 +261,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.DynamicSecrets], querystring: z.object({ projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST.projectSlug), path: z.string().trim().default("/").transform(removeTrailingSlash).describe(DYNAMIC_SECRETS.LIST.path), @@ -284,18 +294,20 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.DynamicSecrets], params: z.object({ - name: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEAES_BY_NAME.name) + name: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEASES_BY_NAME.name) }), querystring: z.object({ - projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEAES_BY_NAME.projectSlug), + projectSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEASES_BY_NAME.projectSlug), path: z .string() .trim() .default("/") .transform(removeTrailingSlash) - .describe(DYNAMIC_SECRETS.LIST_LEAES_BY_NAME.path), - environmentSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEAES_BY_NAME.environmentSlug) + .describe(DYNAMIC_SECRETS.LIST_LEASES_BY_NAME.path), + environmentSlug: z.string().min(1).describe(DYNAMIC_SECRETS.LIST_LEASES_BY_NAME.environmentSlug) }), response: { 200: z.object({ diff --git a/backend/src/ee/routes/v1/group-router.ts b/backend/src/ee/routes/v1/group-router.ts index 67f955ecb..d10e1800b 100644 --- a/backend/src/ee/routes/v1/group-router.ts +++ b/backend/src/ee/routes/v1/group-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { GroupsSchema, OrgMembershipRole, UsersSchema } from "@app/db/schemas"; import { EFilterReturnedUsers } from "@app/ee/services/group/group-types"; -import { GROUPS } from "@app/lib/api-docs"; +import { ApiDocsTags, GROUPS } from "@app/lib/api-docs"; import { slugSchema } from "@app/server/lib/schemas"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -13,6 +13,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { method: "POST", onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Groups], body: z.object({ name: z.string().trim().min(1).max(50).describe(GROUPS.CREATE.name), slug: slugSchema({ min: 5, max: 36 }).optional().describe(GROUPS.CREATE.slug), @@ -40,6 +42,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { method: "GET", onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Groups], params: z.object({ id: z.string().trim().describe(GROUPS.GET_BY_ID.id) }), @@ -65,6 +69,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { method: "GET", onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Groups], response: { 200: GroupsSchema.array() } @@ -87,6 +93,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { method: "PATCH", onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Groups], params: z.object({ id: z.string().trim().describe(GROUPS.UPDATE.id) }), @@ -120,6 +128,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { method: "DELETE", onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Groups], params: z.object({ id: z.string().trim().describe(GROUPS.DELETE.id) }), @@ -145,6 +155,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { url: "/:id/users", onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Groups], params: z.object({ id: z.string().trim().describe(GROUPS.LIST_USERS.id) }), @@ -194,6 +206,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { url: "/:id/users/:username", onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Groups], params: z.object({ id: z.string().trim().describe(GROUPS.ADD_USER.id), username: z.string().trim().describe(GROUPS.ADD_USER.username) @@ -227,6 +241,8 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => { url: "/:id/users/:username", onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Groups], params: z.object({ id: z.string().trim().describe(GROUPS.DELETE_USER.id), username: z.string().trim().describe(GROUPS.DELETE_USER.username) diff --git a/backend/src/ee/routes/v1/identity-project-additional-privilege-router.ts b/backend/src/ee/routes/v1/identity-project-additional-privilege-router.ts index d6b1a4c5c..f64d3c979 100644 --- a/backend/src/ee/routes/v1/identity-project-additional-privilege-router.ts +++ b/backend/src/ee/routes/v1/identity-project-additional-privilege-router.ts @@ -3,7 +3,7 @@ import { z } from "zod"; import { IdentityProjectAdditionalPrivilegeTemporaryMode } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-types"; import { backfillPermissionV1SchemaToV2Schema } from "@app/ee/services/permission/project-permission"; -import { IDENTITY_ADDITIONAL_PRIVILEGE } from "@app/lib/api-docs"; +import { ApiDocsTags, IDENTITY_ADDITIONAL_PRIVILEGE } from "@app/lib/api-docs"; import { UnauthorizedError } from "@app/lib/errors"; import { ms } from "@app/lib/ms"; import { alphaNumericNanoId } from "@app/lib/nanoid"; @@ -25,6 +25,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.IdentitySpecificPrivilegesV1], description: "Create a permanent or a non expiry specific privilege for identity.", security: [ { @@ -85,6 +87,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.IdentitySpecificPrivilegesV1], description: "Create a temporary or a expiring specific privilege for identity.", security: [ { @@ -157,6 +161,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.IdentitySpecificPrivilegesV1], description: "Update a specific privilege of an identity.", security: [ { @@ -240,6 +246,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.IdentitySpecificPrivilegesV1], description: "Delete a specific privilege of an identity.", security: [ { @@ -279,6 +287,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.IdentitySpecificPrivilegesV1], description: "Retrieve details of a specific privilege by privilege slug.", security: [ { @@ -319,6 +329,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.IdentitySpecificPrivilegesV1], description: "List of a specific privilege of an identity in a project.", security: [ { diff --git a/backend/src/ee/routes/v1/project-router.ts b/backend/src/ee/routes/v1/project-router.ts index e3956731e..ab9d1be6c 100644 --- a/backend/src/ee/routes/v1/project-router.ts +++ b/backend/src/ee/routes/v1/project-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { AuditLogsSchema, SecretSnapshotsSchema } from "@app/db/schemas"; import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types"; -import { AUDIT_LOGS, PROJECTS } from "@app/lib/api-docs"; +import { ApiDocsTags, AUDIT_LOGS, PROJECTS } from "@app/lib/api-docs"; import { getLastMidnightDateISO, removeTrailingSlash } from "@app/lib/fn"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -17,6 +17,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Projects], description: "Return project secret snapshots ids", security: [ { diff --git a/backend/src/ee/routes/v1/project-template-router.ts b/backend/src/ee/routes/v1/project-template-router.ts index cabf65337..08d16414b 100644 --- a/backend/src/ee/routes/v1/project-template-router.ts +++ b/backend/src/ee/routes/v1/project-template-router.ts @@ -5,7 +5,7 @@ import { EventType } from "@app/ee/services/audit-log/audit-log-types"; 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 { ProjectTemplates } from "@app/lib/api-docs"; +import { ApiDocsTags, ProjectTemplates } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { slugSchema } from "@app/server/lib/schemas"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -101,6 +101,8 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider) rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectTemplates], description: "List project templates for the current organization.", response: { 200: z.object({ @@ -137,6 +139,8 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider) rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectTemplates], description: "Get a project template by ID.", params: z.object({ templateId: z.string().uuid() @@ -176,6 +180,8 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider) rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectTemplates], description: "Create a project template.", body: z.object({ name: slugSchema({ field: "name" }) @@ -219,6 +225,8 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider) rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectTemplates], description: "Update a project template.", params: z.object({ templateId: z.string().uuid().describe(ProjectTemplates.UPDATE.templateId) }), body: z.object({ @@ -269,6 +277,8 @@ export const registerProjectTemplateRouter = async (server: FastifyZodProvider) rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectTemplates], description: "Delete a project template.", params: z.object({ templateId: z.string().uuid().describe(ProjectTemplates.DELETE.templateId) }), diff --git a/backend/src/ee/routes/v1/snapshot-router.ts b/backend/src/ee/routes/v1/snapshot-router.ts index 494871ec1..3ee80adce 100644 --- a/backend/src/ee/routes/v1/snapshot-router.ts +++ b/backend/src/ee/routes/v1/snapshot-router.ts @@ -1,7 +1,7 @@ import { z } from "zod"; import { SecretSnapshotsSchema } from "@app/db/schemas"; -import { PROJECTS } from "@app/lib/api-docs"; +import { ApiDocsTags, PROJECTS } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { SanitizedTagSchema, secretRawSchema } from "@app/server/routes/sanitizedSchemas"; @@ -65,6 +65,8 @@ export const registerSnapshotRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Projects], description: "Roll back project secrets to those captured in a secret snapshot version.", security: [ { diff --git a/backend/src/ee/routes/v1/ssh-certificate-authority-router.ts b/backend/src/ee/routes/v1/ssh-certificate-authority-router.ts index 783cb9b72..e20d49263 100644 --- a/backend/src/ee/routes/v1/ssh-certificate-authority-router.ts +++ b/backend/src/ee/routes/v1/ssh-certificate-authority-router.ts @@ -6,7 +6,7 @@ import { sanitizedSshCa } from "@app/ee/services/ssh/ssh-certificate-authority-s import { SshCaKeySource, SshCaStatus } from "@app/ee/services/ssh/ssh-certificate-authority-types"; import { SshCertKeyAlgorithm } from "@app/ee/services/ssh-certificate/ssh-certificate-types"; import { sanitizedSshCertificateTemplate } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-schema"; -import { SSH_CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs"; +import { ApiDocsTags, SSH_CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -20,6 +20,8 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.SshCertificateAuthorities], description: "Create SSH CA", body: z .object({ @@ -92,6 +94,8 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.SshCertificateAuthorities], description: "Get SSH CA", params: z.object({ sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.GET.sshCaId) @@ -138,6 +142,8 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SshCertificateAuthorities], description: "Get public key of SSH CA", params: z.object({ sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.GET_PUBLIC_KEY.sshCaId) @@ -163,6 +169,8 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.SshCertificateAuthorities], description: "Update SSH CA", params: z.object({ sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.UPDATE.sshCaId) @@ -216,6 +224,8 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.SshCertificateAuthorities], description: "Delete SSH CA", params: z.object({ sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.DELETE.sshCaId) @@ -261,6 +271,8 @@ export const registerSshCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.SshCertificateAuthorities], description: "Get list of certificate templates for the SSH CA", params: z.object({ sshCaId: z.string().trim().describe(SSH_CERTIFICATE_AUTHORITIES.GET_CERTIFICATE_TEMPLATES.sshCaId) diff --git a/backend/src/ee/routes/v1/ssh-certificate-router.ts b/backend/src/ee/routes/v1/ssh-certificate-router.ts index eb0fc158a..cb576e496 100644 --- a/backend/src/ee/routes/v1/ssh-certificate-router.ts +++ b/backend/src/ee/routes/v1/ssh-certificate-router.ts @@ -3,7 +3,7 @@ import { z } from "zod"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { SshCertType } from "@app/ee/services/ssh/ssh-certificate-authority-types"; import { SshCertKeyAlgorithm } from "@app/ee/services/ssh-certificate/ssh-certificate-types"; -import { SSH_CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs"; +import { ApiDocsTags, SSH_CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs"; import { ms } from "@app/lib/ms"; import { writeLimit } from "@app/server/config/rateLimiter"; import { getTelemetryDistinctId } from "@app/server/lib/telemetry"; @@ -20,6 +20,8 @@ export const registerSshCertRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.SshCertificates], description: "Sign SSH public key", body: z.object({ certificateTemplateId: z @@ -100,6 +102,8 @@ export const registerSshCertRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.SshCertificates], description: "Issue SSH credentials (certificate + key)", body: z.object({ certificateTemplateId: z diff --git a/backend/src/ee/routes/v1/ssh-certificate-template-router.ts b/backend/src/ee/routes/v1/ssh-certificate-template-router.ts index a7dc55661..e44693643 100644 --- a/backend/src/ee/routes/v1/ssh-certificate-template-router.ts +++ b/backend/src/ee/routes/v1/ssh-certificate-template-router.ts @@ -8,7 +8,7 @@ import { isValidHostPattern, isValidUserPattern } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-validators"; -import { SSH_CERTIFICATE_TEMPLATES } from "@app/lib/api-docs"; +import { ApiDocsTags, SSH_CERTIFICATE_TEMPLATES } from "@app/lib/api-docs"; import { ms } from "@app/lib/ms"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -22,6 +22,8 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SshCertificateTemplates], params: z.object({ certificateTemplateId: z.string().describe(SSH_CERTIFICATE_TEMPLATES.GET.certificateTemplateId) }), @@ -61,6 +63,8 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SshCertificateTemplates], body: z .object({ sshCaId: z.string().describe(SSH_CERTIFICATE_TEMPLATES.CREATE.sshCaId), @@ -141,6 +145,8 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SshCertificateTemplates], body: z.object({ status: z.nativeEnum(SshCertTemplateStatus).optional(), name: z @@ -224,6 +230,8 @@ export const registerSshCertificateTemplateRouter = async (server: FastifyZodPro rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SshCertificateTemplates], params: z.object({ certificateTemplateId: z.string().describe(SSH_CERTIFICATE_TEMPLATES.DELETE.certificateTemplateId) }), diff --git a/backend/src/ee/routes/v2/identity-project-additional-privilege-router.ts b/backend/src/ee/routes/v2/identity-project-additional-privilege-router.ts index c8f0ba16c..a6d4459e4 100644 --- a/backend/src/ee/routes/v2/identity-project-additional-privilege-router.ts +++ b/backend/src/ee/routes/v2/identity-project-additional-privilege-router.ts @@ -4,7 +4,7 @@ import { z } from "zod"; import { IdentityProjectAdditionalPrivilegeTemporaryMode } from "@app/ee/services/identity-project-additional-privilege-v2/identity-project-additional-privilege-v2-types"; import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns"; import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission"; -import { IDENTITY_ADDITIONAL_PRIVILEGE_V2 } from "@app/lib/api-docs"; +import { ApiDocsTags, IDENTITY_ADDITIONAL_PRIVILEGE_V2 } from "@app/lib/api-docs"; import { ms } from "@app/lib/ms"; import { alphaNumericNanoId } from "@app/lib/nanoid"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; @@ -21,6 +21,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.IdentitySpecificPrivilegesV2], description: "Add an additional privilege for identity.", security: [ { @@ -84,6 +86,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.IdentitySpecificPrivilegesV2], description: "Update a specific identity privilege.", security: [ { @@ -148,6 +152,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.IdentitySpecificPrivilegesV2], description: "Delete the specified identity privilege.", security: [ { @@ -183,6 +189,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.IdentitySpecificPrivilegesV2], description: "Retrieve details of a specific privilege by id.", security: [ { @@ -218,6 +226,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.IdentitySpecificPrivilegesV2], description: "Retrieve details of a specific privilege by slug.", security: [ { @@ -258,6 +268,8 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.IdentitySpecificPrivilegesV2], description: "List privileges for the specified identity by project.", security: [ { diff --git a/backend/src/ee/routes/v2/project-role-router.ts b/backend/src/ee/routes/v2/project-role-router.ts index 0bb83b8d4..538929316 100644 --- a/backend/src/ee/routes/v2/project-role-router.ts +++ b/backend/src/ee/routes/v2/project-role-router.ts @@ -4,7 +4,7 @@ import { z } from "zod"; import { ProjectMembershipRole, ProjectRolesSchema } from "@app/db/schemas"; import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns"; import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission"; -import { PROJECT_ROLE } from "@app/lib/api-docs"; +import { ApiDocsTags, PROJECT_ROLE } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { slugSchema } from "@app/server/lib/schemas"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -20,6 +20,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectRoles], description: "Create a project role", security: [ { @@ -75,6 +77,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectRoles], description: "Update a project role", security: [ { @@ -130,6 +134,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectRoles], description: "Delete a project role", security: [ { @@ -166,6 +172,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectRoles], description: "List project role", security: [ { @@ -204,6 +212,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectRoles], params: z.object({ projectId: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.projectId), roleSlug: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.roleSlug) diff --git a/backend/src/ee/routes/v2/secret-rotation-v2-routers/secret-rotation-v2-endpoints.ts b/backend/src/ee/routes/v2/secret-rotation-v2-routers/secret-rotation-v2-endpoints.ts index 05d3c7961..17fe14dbf 100644 --- a/backend/src/ee/routes/v2/secret-rotation-v2-routers/secret-rotation-v2-endpoints.ts +++ b/backend/src/ee/routes/v2/secret-rotation-v2-routers/secret-rotation-v2-endpoints.ts @@ -9,7 +9,7 @@ import { TSecretRotationV2GeneratedCredentials, TSecretRotationV2Input } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-types"; -import { SecretRotations } from "@app/lib/api-docs"; +import { ApiDocsTags, SecretRotations } from "@app/lib/api-docs"; import { startsWithVowel } from "@app/lib/fn"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -66,6 +66,8 @@ export const registerSecretRotationEndpoints = < rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretRotations], description: `List the ${rotationType} Rotations for the specified project.`, querystring: z.object({ projectId: z.string().trim().min(1, "Project ID required").describe(SecretRotations.LIST(type).projectId) @@ -109,6 +111,8 @@ export const registerSecretRotationEndpoints = < rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretRotations], description: `Get the specified ${rotationType} Rotation by ID.`, params: z.object({ rotationId: z.string().uuid().describe(SecretRotations.GET_BY_ID(type).rotationId) @@ -151,6 +155,8 @@ export const registerSecretRotationEndpoints = < rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretRotations], description: `Get the specified ${rotationType} Rotation by name, secret path, environment and project ID.`, params: z.object({ rotationName: z @@ -215,6 +221,8 @@ export const registerSecretRotationEndpoints = < rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretRotations], description: `Create ${ startsWithVowel(rotationType) ? "an" : "a" } ${rotationType} Rotation for the specified project.`, @@ -254,6 +262,8 @@ export const registerSecretRotationEndpoints = < rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretRotations], description: `Update the specified ${rotationType} Rotation.`, params: z.object({ rotationId: z.string().uuid().describe(SecretRotations.UPDATE(type).rotationId) @@ -296,6 +306,8 @@ export const registerSecretRotationEndpoints = < rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretRotations], description: `Delete the specified ${rotationType} Rotation.`, params: z.object({ rotationId: z.string().uuid().describe(SecretRotations.DELETE(type).rotationId) @@ -349,6 +361,8 @@ export const registerSecretRotationEndpoints = < rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretRotations], description: `Get the generated credentials for the specified ${rotationType} Rotation.`, params: z.object({ rotationId: z.string().uuid().describe(SecretRotations.GET_GENERATED_CREDENTIALS_BY_ID(type).rotationId) @@ -402,6 +416,8 @@ export const registerSecretRotationEndpoints = < rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretRotations], description: `Rotate the generated credentials for the specified ${rotationType} Rotation.`, params: z.object({ rotationId: z.string().uuid().describe(SecretRotations.ROTATE(type).rotationId) diff --git a/backend/src/ee/routes/v2/secret-rotation-v2-routers/secret-rotation-v2-router.ts b/backend/src/ee/routes/v2/secret-rotation-v2-routers/secret-rotation-v2-router.ts index 56896e0bb..8d28faa6e 100644 --- a/backend/src/ee/routes/v2/secret-rotation-v2-routers/secret-rotation-v2-router.ts +++ b/backend/src/ee/routes/v2/secret-rotation-v2-routers/secret-rotation-v2-router.ts @@ -6,7 +6,7 @@ import { AzureClientSecretRotationListItemSchema } from "@app/ee/services/secret import { MsSqlCredentialsRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/mssql-credentials"; import { PostgresCredentialsRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/postgres-credentials"; import { SecretRotationV2Schema } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-union-schema"; -import { SecretRotations } from "@app/lib/api-docs"; +import { ApiDocsTags, SecretRotations } from "@app/lib/api-docs"; import { readLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -26,6 +26,8 @@ export const registerSecretRotationV2Router = async (server: FastifyZodProvider) rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretRotations], description: "List the available Secret Rotation Options.", response: { 200: z.object({ @@ -47,6 +49,8 @@ export const registerSecretRotationV2Router = async (server: FastifyZodProvider) rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretRotations], description: "List all the Secret Rotations for the specified project.", querystring: z.object({ projectId: z.string().trim().min(1, "Project ID required").describe(SecretRotations.LIST().projectId) diff --git a/backend/src/ee/services/audit-log/audit-log-types.ts b/backend/src/ee/services/audit-log/audit-log-types.ts index 91464bc0b..a31200a1b 100644 --- a/backend/src/ee/services/audit-log/audit-log-types.ts +++ b/backend/src/ee/services/audit-log/audit-log-types.ts @@ -234,6 +234,7 @@ export enum EventType { GET_PROJECT_KMS_BACKUP = "get-project-kms-backup", LOAD_PROJECT_KMS_BACKUP = "load-project-kms-backup", ORG_ADMIN_ACCESS_PROJECT = "org-admin-accessed-project", + ORG_ADMIN_BYPASS_SSO = "org-admin-bypassed-sso", CREATE_CERTIFICATE_TEMPLATE = "create-certificate-template", UPDATE_CERTIFICATE_TEMPLATE = "update-certificate-template", DELETE_CERTIFICATE_TEMPLATE = "delete-certificate-template", @@ -1907,6 +1908,11 @@ interface OrgAdminAccessProjectEvent { }; // no metadata yet } +interface OrgAdminBypassSSOEvent { + type: EventType.ORG_ADMIN_BYPASS_SSO; + metadata: Record; // no metadata yet +} + interface CreateCertificateTemplateEstConfig { type: EventType.CREATE_CERTIFICATE_TEMPLATE_EST_CONFIG; metadata: { @@ -2656,6 +2662,7 @@ export type Event = | GetProjectKmsBackupEvent | LoadProjectKmsBackupEvent | OrgAdminAccessProjectEvent + | OrgAdminBypassSSOEvent | CreateCertificateTemplate | UpdateCertificateTemplate | GetCertificateTemplate diff --git a/backend/src/ee/services/dynamic-secret-lease/dynamic-secret-lease-service.ts b/backend/src/ee/services/dynamic-secret-lease/dynamic-secret-lease-service.ts index 88f2d90f1..4adf8b7e2 100644 --- a/backend/src/ee/services/dynamic-secret-lease/dynamic-secret-lease-service.ts +++ b/backend/src/ee/services/dynamic-secret-lease/dynamic-secret-lease-service.ts @@ -130,7 +130,17 @@ export const dynamicSecretLeaseServiceFactory = ({ if (expireAt > maxExpiryDate) throw new BadRequestError({ message: "TTL cannot be larger than max TTL" }); } - const { entityId, data } = await selectedProvider.create(decryptedStoredInput, expireAt.getTime()); + let result; + try { + result = await selectedProvider.create(decryptedStoredInput, expireAt.getTime()); + } catch (error: unknown) { + if (error && typeof error === "object" && error !== null && "sqlMessage" in error) { + throw new BadRequestError({ message: error.sqlMessage as string }); + } + throw error; + } + const { entityId, data } = result; + const dynamicSecretLease = await dynamicSecretLeaseDAL.create({ expireAt, version: 1, diff --git a/backend/src/ee/services/secret-replication/secret-replication-service.ts b/backend/src/ee/services/secret-replication/secret-replication-service.ts index 480e80028..90fdf561e 100644 --- a/backend/src/ee/services/secret-replication/secret-replication-service.ts +++ b/backend/src/ee/services/secret-replication/secret-replication-service.ts @@ -267,7 +267,6 @@ export const secretReplicationServiceFactory = ({ const sourceLocalSecrets = await secretV2BridgeDAL.find({ folderId: folder.id, type: SecretType.Shared }); const sourceSecretImports = await secretImportDAL.find({ folderId: folder.id }); const sourceImportedSecrets = await fnSecretsV2FromImports({ - projectId, secretImports: sourceSecretImports, secretDAL: secretV2BridgeDAL, folderDAL, diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index 109b7047c..e02df659d 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -8,6 +8,51 @@ import { APP_CONNECTION_NAME_MAP } from "@app/services/app-connection/app-connec import { SecretSync } from "@app/services/secret-sync/secret-sync-enums"; import { SECRET_SYNC_CONNECTION_MAP, SECRET_SYNC_NAME_MAP } from "@app/services/secret-sync/secret-sync-maps"; +export enum ApiDocsTags { + Identities = "Identities", + TokenAuth = "Token Auth", + UniversalAuth = "Universal Auth", + GcpAuth = "GCP Auth", + AwsAuth = "AWS Auth", + AzureAuth = "Azure Auth", + KubernetesAuth = "Kubernetes Auth", + JwtAuth = "JWT Auth", + OidcAuth = "OIDC Auth", + Groups = "Groups", + Organizations = "Organizations", + Projects = "Projects", + ProjectUsers = "Project Users", + ProjectGroups = "Project Groups", + ProjectIdentities = "Project Identities", + ProjectRoles = "Project Roles", + ProjectTemplates = "Project Templates", + Environments = "Environments", + Folders = "Folders", + SecretTags = "Secret Tags", + Secrets = "Secrets", + DynamicSecrets = "Dynamic Secrets", + SecretImports = "Secret Imports", + SecretRotations = "Secret Rotations", + IdentitySpecificPrivilegesV1 = "Identity Specific Privileges", + IdentitySpecificPrivilegesV2 = "Identity Specific Privileges V2", + AppConnections = "App Connections", + SecretSyncs = "Secret Syncs", + Integrations = "Integrations", + ServiceTokens = "Service Tokens", + AuditLogs = "Audit Logs", + PkiCertificateAuthorities = "PKI Certificate Authorities", + PkiCertificates = "PKI Certificates", + PkiCertificateTemplates = "PKI Certificate Templates", + PkiCertificateCollections = "PKI Certificate Collections", + PkiAlerting = "PKI Alerting", + SshCertificates = "SSH Certificates", + SshCertificateAuthorities = "SSH Certificate Authorities", + SshCertificateTemplates = "SSH Certificate Templates", + KmsKeys = "KMS Keys", + KmsEncryption = "KMS Encryption", + KmsSigning = "KMS Signing" +} + export const GROUPS = { CREATE: { name: "The name of the group to create.", @@ -888,7 +933,7 @@ export const DYNAMIC_SECRETS = { environmentSlug: "The slug of the environment to list folders from.", path: "The path to list folders from." }, - LIST_LEAES_BY_NAME: { + LIST_LEASES_BY_NAME: { projectSlug: "The slug of the project to create dynamic secret in.", environmentSlug: "The slug of the environment to list folders from.", path: "The path to list folders from.", diff --git a/backend/src/main.ts b/backend/src/main.ts index 80d98abcf..c3b5a0900 100644 --- a/backend/src/main.ts +++ b/backend/src/main.ts @@ -73,6 +73,7 @@ const run = async () => { // eslint-disable-next-line process.on("SIGINT", async () => { await server.close(); + await queue.shutdown(); await db.destroy(); await removeTemporaryBaseDirectory(); hsmModule.finalize(); @@ -82,19 +83,22 @@ const run = async () => { // eslint-disable-next-line process.on("SIGTERM", async () => { await server.close(); + await queue.shutdown(); await db.destroy(); await removeTemporaryBaseDirectory(); hsmModule.finalize(); process.exit(0); }); - process.on("uncaughtException", (error) => { - logger.error(error, "CRITICAL ERROR: Uncaught Exception"); - }); + if (!envConfig.isDevelopmentMode) { + process.on("uncaughtException", (error) => { + logger.error(error, "CRITICAL ERROR: Uncaught Exception"); + }); - process.on("unhandledRejection", (error) => { - logger.error(error, "CRITICAL ERROR: Unhandled Promise Rejection"); - }); + process.on("unhandledRejection", (error) => { + logger.error(error, "CRITICAL ERROR: Unhandled Promise Rejection"); + }); + } await server.listen({ port: envConfig.PORT, diff --git a/backend/src/server/plugins/fastify-zod.ts b/backend/src/server/plugins/fastify-zod.ts index 02636a066..4e898a9b5 100644 --- a/backend/src/server/plugins/fastify-zod.ts +++ b/backend/src/server/plugins/fastify-zod.ts @@ -49,14 +49,17 @@ function resolveSchema(maybeSchema: ZodAny | { properties: ZodAny }): Pick { - return ({ schema, url }: { schema: Schema; url: string }) => { + return ({ schema = {}, url }: { schema: Schema; url: string }) => { if (!schema) { return { - schema, + schema: { hide: true }, url }; } + if (typeof schema.hide === "undefined") { + schema.hide = true; + } const { response, headers, querystring, body, params, hide, ...rest } = schema; const transformed: FreeformRecord = {}; diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index c9f2811b5..2c1b768fb 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -596,7 +596,14 @@ export const registerRoutes = async ( kmsService }); - const loginService = authLoginServiceFactory({ userDAL, smtpService, tokenService, orgDAL, totpService }); + const loginService = authLoginServiceFactory({ + userDAL, + smtpService, + tokenService, + orgDAL, + totpService, + auditLogService + }); const passwordService = authPaswordServiceFactory({ tokenService, smtpService, @@ -1089,7 +1096,8 @@ export const registerRoutes = async ( secretApprovalRequestSecretDAL, kmsService, snapshotService, - resourceMetadataDAL + resourceMetadataDAL, + keyStore }); const secretApprovalRequestService = secretApprovalRequestServiceFactory({ diff --git a/backend/src/server/routes/v1/app-connection-routers/app-connection-endpoints.ts b/backend/src/server/routes/v1/app-connection-routers/app-connection-endpoints.ts index dfb451a4c..0bc8f7c59 100644 --- a/backend/src/server/routes/v1/app-connection-routers/app-connection-endpoints.ts +++ b/backend/src/server/routes/v1/app-connection-routers/app-connection-endpoints.ts @@ -1,7 +1,7 @@ import { z } from "zod"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { AppConnections } from "@app/lib/api-docs"; +import { ApiDocsTags, AppConnections } from "@app/lib/api-docs"; import { startsWithVowel } from "@app/lib/fn"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -43,6 +43,8 @@ export const registerAppConnectionEndpoints = rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.AppConnections], description: "List the available App Connection Options.", response: { 200: z.object({ @@ -113,6 +116,8 @@ export const registerAppConnectionRouter = async (server: FastifyZodProvider) => rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.AppConnections], description: "List all the App Connections for the current organization.", response: { 200: z.object({ appConnections: SanitizedAppConnectionSchema.array() }) diff --git a/backend/src/server/routes/v1/certificate-authority-router.ts b/backend/src/server/routes/v1/certificate-authority-router.ts index b108215ca..f6538b797 100644 --- a/backend/src/server/routes/v1/certificate-authority-router.ts +++ b/backend/src/server/routes/v1/certificate-authority-router.ts @@ -3,7 +3,7 @@ import { z } from "zod"; import { CertificateAuthoritiesSchema, CertificateTemplatesSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs"; +import { ApiDocsTags, CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs"; import { ms } from "@app/lib/ms"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { getTelemetryDistinctId } from "@app/server/lib/telemetry"; @@ -26,6 +26,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Create CA", body: z .object({ @@ -105,6 +107,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Get CA", params: z.object({ caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.GET.caId) @@ -151,6 +155,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Get DER-encoded certificate of CA", params: z.object({ caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.GET_CERT_BY_ID.caId), @@ -177,6 +183,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Update CA", params: z.object({ caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.UPDATE.caId) @@ -231,6 +239,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Delete CA", params: z.object({ caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.DELETE.caId) @@ -276,6 +286,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Get CA CSR", params: z.object({ caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.GET_CSR.caId) @@ -321,6 +333,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Perform CA certificate renewal", params: z.object({ caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.RENEW_CA_CERT.caId) @@ -376,6 +390,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Get list of past and current CA certificates for a CA", params: z.object({ caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.GET_CA_CERTS.caId) @@ -424,6 +440,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Get current CA cert and cert chain of a CA", params: z.object({ caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.GET_CERT.caId) @@ -473,6 +491,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Create intermediate CA certificate from parent CA", params: z.object({ caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.SIGN_INTERMEDIATE.caId) @@ -536,6 +556,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Import certificate and chain to CA", params: z.object({ caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.IMPORT_CERT.caId) @@ -588,6 +610,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Issue certificate from CA", params: z.object({ caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.caId) @@ -679,6 +703,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Sign certificate from CA", params: z.object({ caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.caId) @@ -770,6 +796,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Get list of certificate templates for the CA", params: z.object({ caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.caId) @@ -815,6 +843,8 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], description: "Get list of CRLs of the CA", params: z.object({ caId: z.string().trim().describe(CERTIFICATE_AUTHORITIES.GET_CRLS.caId) diff --git a/backend/src/server/routes/v1/certificate-router.ts b/backend/src/server/routes/v1/certificate-router.ts index 3101393bd..ea33e948f 100644 --- a/backend/src/server/routes/v1/certificate-router.ts +++ b/backend/src/server/routes/v1/certificate-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { CertificatesSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { CERTIFICATE_AUTHORITIES, CERTIFICATES } from "@app/lib/api-docs"; +import { ApiDocsTags, CERTIFICATE_AUTHORITIES, CERTIFICATES } from "@app/lib/api-docs"; import { ms } from "@app/lib/ms"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { getTelemetryDistinctId } from "@app/server/lib/telemetry"; @@ -24,6 +24,8 @@ export const registerCertRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificates], description: "Get certificate", params: z.object({ serialNumber: z.string().trim().describe(CERTIFICATES.GET.serialNumber) @@ -70,6 +72,8 @@ export const registerCertRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificates], description: "Issue certificate", body: z .object({ @@ -181,6 +185,8 @@ export const registerCertRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificates], description: "Sign certificate", body: z .object({ @@ -292,6 +298,8 @@ export const registerCertRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificates], description: "Revoke", params: z.object({ serialNumber: z.string().trim().describe(CERTIFICATES.REVOKE.serialNumber) @@ -346,6 +354,8 @@ export const registerCertRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificates], description: "Delete certificate", params: z.object({ serialNumber: z.string().trim().describe(CERTIFICATES.DELETE.serialNumber) @@ -392,6 +402,8 @@ export const registerCertRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificates], description: "Get certificate body of certificate", params: z.object({ serialNumber: z.string().trim().describe(CERTIFICATES.GET_CERT.serialNumber) diff --git a/backend/src/server/routes/v1/certificate-template-router.ts b/backend/src/server/routes/v1/certificate-template-router.ts index 2217445cb..b0c186206 100644 --- a/backend/src/server/routes/v1/certificate-template-router.ts +++ b/backend/src/server/routes/v1/certificate-template-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { CertificateTemplateEstConfigsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { CERTIFICATE_TEMPLATES } from "@app/lib/api-docs"; +import { ApiDocsTags, CERTIFICATE_TEMPLATES } from "@app/lib/api-docs"; import { ms } from "@app/lib/ms"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -26,6 +26,8 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateTemplates], params: z.object({ certificateTemplateId: z.string().describe(CERTIFICATE_TEMPLATES.GET.certificateTemplateId) }), @@ -65,6 +67,8 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateTemplates], body: z.object({ caId: z.string().describe(CERTIFICATE_TEMPLATES.CREATE.caId), pkiCollectionId: z.string().optional().describe(CERTIFICATE_TEMPLATES.CREATE.pkiCollectionId), @@ -132,6 +136,8 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateTemplates], body: z.object({ caId: z.string().optional().describe(CERTIFICATE_TEMPLATES.UPDATE.caId), pkiCollectionId: z.string().optional().describe(CERTIFICATE_TEMPLATES.UPDATE.pkiCollectionId), @@ -198,6 +204,8 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateTemplates], params: z.object({ certificateTemplateId: z.string().describe(CERTIFICATE_TEMPLATES.DELETE.certificateTemplateId) }), @@ -238,6 +246,8 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateTemplates], description: "Create Certificate Template EST configuration", params: z.object({ certificateTemplateId: z.string().trim() @@ -292,6 +302,8 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateTemplates], description: "Update Certificate Template EST configuration", params: z.object({ certificateTemplateId: z.string().trim() @@ -340,6 +352,8 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateTemplates], description: "Get Certificate Template EST configuration", params: z.object({ certificateTemplateId: z.string().trim() diff --git a/backend/src/server/routes/v1/cmek-router.ts b/backend/src/server/routes/v1/cmek-router.ts index 64f47f980..c8fd485a7 100644 --- a/backend/src/server/routes/v1/cmek-router.ts +++ b/backend/src/server/routes/v1/cmek-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { InternalKmsSchema, KmsKeysSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { KMS } from "@app/lib/api-docs"; +import { ApiDocsTags, KMS } from "@app/lib/api-docs"; import { getBase64SizeInBytes, isBase64 } from "@app/lib/base64"; import { AllowedEncryptionKeyAlgorithms, SymmetricKeyAlgorithm } from "@app/lib/crypto/cipher"; import { AsymmetricKeyAlgorithm, SigningAlgorithm } from "@app/lib/crypto/sign"; @@ -46,6 +46,8 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.KmsKeys], description: "Create KMS key", body: z .object({ @@ -138,6 +140,8 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.KmsKeys], description: "Update KMS key", params: z.object({ keyId: z.string().uuid().describe(KMS.UPDATE_KEY.keyId) @@ -187,6 +191,8 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.KmsKeys], description: "Delete KMS key", params: z.object({ keyId: z.string().uuid().describe(KMS.DELETE_KEY.keyId) @@ -229,6 +235,8 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.KmsKeys], description: "List KMS keys", querystring: z.object({ projectId: z.string().describe(KMS.LIST_KEYS.projectId), @@ -280,6 +288,8 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.KmsKeys], description: "Get KMS key by ID", params: z.object({ keyId: z.string().uuid().describe(KMS.GET_KEY_BY_ID.keyId) @@ -321,6 +331,8 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.KmsKeys], description: "Get KMS key by name", params: z.object({ keyName: slugSchema({ field: "Key name" }).describe(KMS.GET_KEY_BY_NAME.keyName) @@ -367,6 +379,8 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.KmsEncryption], description: "Encrypt data with KMS key", params: z.object({ keyId: z.string().uuid().describe(KMS.ENCRYPT.keyId) @@ -412,6 +426,8 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.KmsSigning], description: "Get the public key for a KMS key that is used for signing and verifying data. This endpoint is only available for asymmetric keys.", params: z.object({ @@ -454,6 +470,8 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.KmsSigning], description: "List all available signing algorithms for a KMS key", params: z.object({ keyId: z.string().uuid().describe(KMS.LIST_SIGNING_ALGORITHMS.keyId) @@ -495,6 +513,8 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.KmsSigning], description: "Sign data with a KMS key.", params: z.object({ keyId: z.string().uuid().describe(KMS.SIGN.keyId) @@ -548,6 +568,8 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.KmsSigning], description: "Verify data signatures with a KMS key.", params: z.object({ keyId: z.string().uuid().describe(KMS.VERIFY.keyId) @@ -604,6 +626,8 @@ export const registerCmekRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.KmsEncryption], description: "Decrypt data with KMS key", params: z.object({ keyId: z.string().uuid().describe(KMS.DECRYPT.keyId) diff --git a/backend/src/server/routes/v1/identity-access-token-router.ts b/backend/src/server/routes/v1/identity-access-token-router.ts index 7ed62e679..20ed8d150 100644 --- a/backend/src/server/routes/v1/identity-access-token-router.ts +++ b/backend/src/server/routes/v1/identity-access-token-router.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { UNIVERSAL_AUTH } from "@app/lib/api-docs"; +import { ApiDocsTags, UNIVERSAL_AUTH } from "@app/lib/api-docs"; import { writeLimit } from "@app/server/config/rateLimiter"; export const registerIdentityAccessTokenRouter = async (server: FastifyZodProvider) => { @@ -11,6 +11,8 @@ export const registerIdentityAccessTokenRouter = async (server: FastifyZodProvid rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.UniversalAuth], description: "Renew access token", body: z.object({ accessToken: z.string().trim().describe(UNIVERSAL_AUTH.RENEW_ACCESS_TOKEN.accessToken) @@ -44,6 +46,8 @@ export const registerIdentityAccessTokenRouter = async (server: FastifyZodProvid rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.UniversalAuth], description: "Revoke access token", body: z.object({ accessToken: z.string().trim().describe(UNIVERSAL_AUTH.REVOKE_ACCESS_TOKEN.accessToken) diff --git a/backend/src/server/routes/v1/identity-aws-iam-auth-router.ts b/backend/src/server/routes/v1/identity-aws-iam-auth-router.ts index 82387a3cc..effd66a68 100644 --- a/backend/src/server/routes/v1/identity-aws-iam-auth-router.ts +++ b/backend/src/server/routes/v1/identity-aws-iam-auth-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { IdentityAwsAuthsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { AWS_AUTH } from "@app/lib/api-docs"; +import { ApiDocsTags, AWS_AUTH } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -21,6 +21,8 @@ export const registerIdentityAwsAuthRouter = async (server: FastifyZodProvider) rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.AwsAuth], description: "Login with AWS Auth", body: z.object({ identityId: z.string().trim().describe(AWS_AUTH.LOGIN.identityId), @@ -71,6 +73,8 @@ export const registerIdentityAwsAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.AwsAuth], description: "Attach AWS Auth configuration onto identity", security: [ { @@ -165,6 +169,8 @@ export const registerIdentityAwsAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.AwsAuth], description: "Update AWS Auth configuration on identity", security: [ { @@ -247,6 +253,8 @@ export const registerIdentityAwsAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.AwsAuth], description: "Retrieve AWS Auth configuration on identity", security: [ { @@ -293,6 +301,8 @@ export const registerIdentityAwsAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.AwsAuth], description: "Delete AWS Auth configuration on identity", security: [ { diff --git a/backend/src/server/routes/v1/identity-azure-auth-router.ts b/backend/src/server/routes/v1/identity-azure-auth-router.ts index 1cf59e682..9053bc2e3 100644 --- a/backend/src/server/routes/v1/identity-azure-auth-router.ts +++ b/backend/src/server/routes/v1/identity-azure-auth-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { IdentityAzureAuthsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { AZURE_AUTH } from "@app/lib/api-docs"; +import { ApiDocsTags, AZURE_AUTH } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -18,6 +18,8 @@ export const registerIdentityAzureAuthRouter = async (server: FastifyZodProvider rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.AzureAuth], description: "Login with Azure Auth", body: z.object({ identityId: z.string().trim().describe(AZURE_AUTH.LOGIN.identityId), @@ -66,6 +68,8 @@ export const registerIdentityAzureAuthRouter = async (server: FastifyZodProvider }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.AzureAuth], description: "Attach Azure Auth configuration onto identity", security: [ { @@ -159,6 +163,8 @@ export const registerIdentityAzureAuthRouter = async (server: FastifyZodProvider }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.AzureAuth], description: "Update Azure Auth configuration on identity", security: [ { @@ -247,6 +253,8 @@ export const registerIdentityAzureAuthRouter = async (server: FastifyZodProvider }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.AzureAuth], description: "Retrieve Azure Auth configuration on identity", security: [ { @@ -294,6 +302,8 @@ export const registerIdentityAzureAuthRouter = async (server: FastifyZodProvider }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.AzureAuth], description: "Delete Azure Auth configuration on identity", security: [ { diff --git a/backend/src/server/routes/v1/identity-gcp-auth-router.ts b/backend/src/server/routes/v1/identity-gcp-auth-router.ts index d269072d9..b83faf9d9 100644 --- a/backend/src/server/routes/v1/identity-gcp-auth-router.ts +++ b/backend/src/server/routes/v1/identity-gcp-auth-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { IdentityGcpAuthsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { GCP_AUTH } from "@app/lib/api-docs"; +import { ApiDocsTags, GCP_AUTH } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -18,9 +18,11 @@ export const registerIdentityGcpAuthRouter = async (server: FastifyZodProvider) rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.GcpAuth], description: "Login with GCP Auth", body: z.object({ - identityId: z.string().trim().describe(GCP_AUTH.LOGIN.identityId).trim(), + identityId: z.string().trim().describe(GCP_AUTH.LOGIN.identityId), jwt: z.string() }), response: { @@ -66,6 +68,8 @@ export const registerIdentityGcpAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.GcpAuth], description: "Attach GCP Auth configuration onto identity", security: [ { @@ -157,6 +161,8 @@ export const registerIdentityGcpAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.GcpAuth], description: "Update GCP Auth configuration on identity", security: [ { @@ -241,6 +247,8 @@ export const registerIdentityGcpAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.GcpAuth], description: "Retrieve GCP Auth configuration on identity", security: [ { @@ -288,6 +296,8 @@ export const registerIdentityGcpAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.GcpAuth], description: "Delete GCP Auth configuration on identity", security: [ { diff --git a/backend/src/server/routes/v1/identity-jwt-auth-router.ts b/backend/src/server/routes/v1/identity-jwt-auth-router.ts index bb09898a3..373a8b927 100644 --- a/backend/src/server/routes/v1/identity-jwt-auth-router.ts +++ b/backend/src/server/routes/v1/identity-jwt-auth-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { IdentityJwtAuthsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { JWT_AUTH } from "@app/lib/api-docs"; +import { ApiDocsTags, JWT_AUTH } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -94,6 +94,8 @@ export const registerIdentityJwtAuthRouter = async (server: FastifyZodProvider) rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.JwtAuth], description: "Login with JWT Auth", body: z.object({ identityId: z.string().trim().describe(JWT_AUTH.LOGIN.identityId), @@ -144,6 +146,8 @@ export const registerIdentityJwtAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.JwtAuth], description: "Attach JWT Auth configuration onto identity", security: [ { @@ -211,6 +215,8 @@ export const registerIdentityJwtAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.JwtAuth], description: "Update JWT Auth configuration on identity", security: [ { @@ -275,6 +281,8 @@ export const registerIdentityJwtAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.JwtAuth], description: "Retrieve JWT Auth configuration on identity", security: [ { @@ -322,6 +330,8 @@ export const registerIdentityJwtAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.JwtAuth], description: "Delete JWT Auth configuration on identity", security: [ { diff --git a/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts b/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts index 0105afd76..21759e0cd 100644 --- a/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts +++ b/backend/src/server/routes/v1/identity-kubernetes-auth-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { IdentityKubernetesAuthsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { KUBERNETES_AUTH } from "@app/lib/api-docs"; +import { ApiDocsTags, KUBERNETES_AUTH } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -35,6 +35,8 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.KubernetesAuth], description: "Login with Kubernetes Auth", body: z.object({ identityId: z.string().trim().describe(KUBERNETES_AUTH.LOGIN.identityId), @@ -85,6 +87,8 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.KubernetesAuth], description: "Attach Kubernetes Auth configuration onto identity", security: [ { @@ -182,6 +186,8 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.KubernetesAuth], description: "Update Kubernetes Auth configuration on identity", security: [ { @@ -278,6 +284,8 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.KubernetesAuth], description: "Retrieve Kubernetes Auth configuration on identity", security: [ { @@ -325,6 +333,8 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.KubernetesAuth], description: "Delete Kubernetes Auth configuration on identity", security: [ { diff --git a/backend/src/server/routes/v1/identity-oidc-auth-router.ts b/backend/src/server/routes/v1/identity-oidc-auth-router.ts index 4a7b66146..74cd94eb5 100644 --- a/backend/src/server/routes/v1/identity-oidc-auth-router.ts +++ b/backend/src/server/routes/v1/identity-oidc-auth-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { IdentityOidcAuthsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { OIDC_AUTH } from "@app/lib/api-docs"; +import { ApiDocsTags, OIDC_AUTH } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -42,6 +42,8 @@ export const registerIdentityOidcAuthRouter = async (server: FastifyZodProvider) rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.OidcAuth], description: "Login with OIDC Auth", body: z.object({ identityId: z.string().trim().describe(OIDC_AUTH.LOGIN.identityId), @@ -96,6 +98,8 @@ export const registerIdentityOidcAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.OidcAuth], description: "Attach OIDC Auth configuration onto identity", security: [ { @@ -195,6 +199,8 @@ export const registerIdentityOidcAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.OidcAuth], description: "Update OIDC Auth configuration on identity", security: [ { @@ -292,6 +298,8 @@ export const registerIdentityOidcAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.OidcAuth], description: "Retrieve OIDC Auth configuration on identity", security: [ { @@ -339,6 +347,8 @@ export const registerIdentityOidcAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.OidcAuth], description: "Delete OIDC Auth configuration on identity", security: [ { diff --git a/backend/src/server/routes/v1/identity-router.ts b/backend/src/server/routes/v1/identity-router.ts index 107a4b9ef..7731aad98 100644 --- a/backend/src/server/routes/v1/identity-router.ts +++ b/backend/src/server/routes/v1/identity-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { IdentitiesSchema, IdentityOrgMembershipsSchema, OrgMembershipRole, OrgRolesSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { IDENTITIES } from "@app/lib/api-docs"; +import { ApiDocsTags, IDENTITIES } from "@app/lib/api-docs"; import { buildSearchZodSchema, SearchResourceOperators } from "@app/lib/search-resource/search"; import { OrderByDirection } from "@app/lib/types"; import { CharacterType, zodValidateCharacters } from "@app/lib/validator/validate-string"; @@ -32,6 +32,8 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Identities], description: "Create identity", security: [ { @@ -100,6 +102,8 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Identities], description: "Update identity", security: [ { @@ -158,6 +162,8 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Identities], description: "Delete identity", security: [ { @@ -205,6 +211,8 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Identities], description: "Get an identity by id", security: [ { @@ -260,6 +268,8 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Identities], description: "List identities", security: [ { @@ -308,6 +318,8 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Identities], description: "Search identities", security: [ { diff --git a/backend/src/server/routes/v1/identity-token-auth-router.ts b/backend/src/server/routes/v1/identity-token-auth-router.ts index d6e7259be..e22c41889 100644 --- a/backend/src/server/routes/v1/identity-token-auth-router.ts +++ b/backend/src/server/routes/v1/identity-token-auth-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { IdentityAccessTokensSchema, IdentityTokenAuthsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { TOKEN_AUTH } from "@app/lib/api-docs"; +import { ApiDocsTags, TOKEN_AUTH } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -18,6 +18,8 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.TokenAuth], description: "Attach Token Auth configuration onto identity", security: [ { @@ -108,6 +110,8 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.TokenAuth], description: "Update Token Auth configuration on identity", security: [ { @@ -192,6 +196,8 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.TokenAuth], description: "Retrieve Token Auth configuration on identity", security: [ { @@ -239,6 +245,8 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.TokenAuth], description: "Delete Token Auth configuration on identity", security: [ { @@ -287,6 +295,8 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.TokenAuth], description: "Create token for identity with Token Auth", security: [ { @@ -349,6 +359,8 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.TokenAuth], description: "Get tokens for identity with Token Auth", security: [ { @@ -402,6 +414,8 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.TokenAuth], description: "Update token for identity with Token Auth", security: [ { @@ -456,6 +470,8 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.TokenAuth], description: "Revoke token for identity with Token Auth", security: [ { diff --git a/backend/src/server/routes/v1/identity-universal-auth-router.ts b/backend/src/server/routes/v1/identity-universal-auth-router.ts index 5a9363f3d..6fe4c7a85 100644 --- a/backend/src/server/routes/v1/identity-universal-auth-router.ts +++ b/backend/src/server/routes/v1/identity-universal-auth-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { IdentityUaClientSecretsSchema, IdentityUniversalAuthsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { UNIVERSAL_AUTH } from "@app/lib/api-docs"; +import { ApiDocsTags, UNIVERSAL_AUTH } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -30,6 +30,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.UniversalAuth], description: "Login with Universal Auth", body: z.object({ clientId: z.string().trim().describe(UNIVERSAL_AUTH.LOGIN.clientId), @@ -78,6 +80,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.UniversalAuth], description: "Attach Universal Auth configuration onto identity", security: [ { @@ -175,6 +179,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.UniversalAuth], description: "Update Universal Auth configuration on identity", security: [ { @@ -271,6 +277,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.UniversalAuth], description: "Retrieve Universal Auth configuration on identity", security: [ { @@ -318,6 +326,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.UniversalAuth], description: "Delete Universal Auth configuration on identity", security: [ { @@ -365,6 +375,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.UniversalAuth], description: "Create Universal Auth Client Secret for identity", security: [ { @@ -421,6 +433,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.UniversalAuth], description: "List Universal Auth Client Secrets for identity", security: [ { @@ -469,6 +483,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.UniversalAuth], description: "Get Universal Auth Client Secret for identity", security: [ { @@ -519,6 +535,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.UniversalAuth], description: "Revoke Universal Auth Client Secrets for identity", security: [ { diff --git a/backend/src/server/routes/v1/integration-auth-router.ts b/backend/src/server/routes/v1/integration-auth-router.ts index bca11cbf3..e5156724d 100644 --- a/backend/src/server/routes/v1/integration-auth-router.ts +++ b/backend/src/server/routes/v1/integration-auth-router.ts @@ -1,7 +1,7 @@ import { z } from "zod"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { INTEGRATION_AUTH } from "@app/lib/api-docs"; +import { ApiDocsTags, INTEGRATION_AUTH } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -19,6 +19,8 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Integrations], description: "List of integrations available.", security: [ { @@ -57,6 +59,8 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Integrations], description: "Get details of an integration authorization by auth object id.", security: [ { @@ -92,6 +96,8 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Integrations], description: "Update the integration authentication object required for syncing secrets.", security: [ { @@ -153,6 +159,8 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Integrations], description: "Remove all integration's auth object from the project.", security: [ { @@ -202,6 +210,8 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Integrations], description: "Remove an integration auth object by object id.", security: [ { @@ -294,6 +304,8 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Integrations], description: "Create the integration authentication object required for syncing secrets.", security: [ { diff --git a/backend/src/server/routes/v1/integration-router.ts b/backend/src/server/routes/v1/integration-router.ts index f0c28478c..f3964e7b7 100644 --- a/backend/src/server/routes/v1/integration-router.ts +++ b/backend/src/server/routes/v1/integration-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { IntegrationsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { INTEGRATION } from "@app/lib/api-docs"; +import { ApiDocsTags, INTEGRATION } from "@app/lib/api-docs"; import { removeTrailingSlash, shake } from "@app/lib/fn"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { getTelemetryDistinctId } from "@app/server/lib/telemetry"; @@ -22,6 +22,8 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Integrations], description: "Create an integration to sync secrets.", security: [ { @@ -119,6 +121,8 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Integrations], description: "Update an integration by integration id", security: [ { @@ -178,6 +182,8 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Integrations], description: "Get an integration by integration id", security: [ { @@ -247,6 +253,8 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Integrations], description: "Remove an integration using the integration object ID", security: [ { @@ -315,6 +323,8 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Integrations], description: "Manually trigger sync of an integration by integration id", security: [ { diff --git a/backend/src/server/routes/v1/organization-router.ts b/backend/src/server/routes/v1/organization-router.ts index 90ca3d255..22314b54b 100644 --- a/backend/src/server/routes/v1/organization-router.ts +++ b/backend/src/server/routes/v1/organization-router.ts @@ -9,7 +9,7 @@ import { UsersSchema } from "@app/db/schemas"; import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types"; -import { AUDIT_LOGS, ORGANIZATIONS } from "@app/lib/api-docs"; +import { ApiDocsTags, AUDIT_LOGS, ORGANIZATIONS } from "@app/lib/api-docs"; import { getLastMidnightDateISO, removeTrailingSlash } from "@app/lib/fn"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { GenericResourceNameSchema, slugSchema } from "@app/server/lib/schemas"; @@ -109,6 +109,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.AuditLogs], description: "Get all audit logs for an organization", querystring: z.object({ projectId: z.string().optional().describe(AUDIT_LOGS.EXPORT.projectId), diff --git a/backend/src/server/routes/v1/pki-alert-router.ts b/backend/src/server/routes/v1/pki-alert-router.ts index f64ec9e47..43ce91e88 100644 --- a/backend/src/server/routes/v1/pki-alert-router.ts +++ b/backend/src/server/routes/v1/pki-alert-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { PkiAlertsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { ALERTS } from "@app/lib/api-docs"; +import { ALERTS, ApiDocsTags } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -16,6 +16,8 @@ export const registerPkiAlertRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiAlerting], description: "Create PKI alert", body: z.object({ projectId: z.string().trim().describe(ALERTS.CREATE.projectId), @@ -68,6 +70,8 @@ export const registerPkiAlertRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiAlerting], description: "Get PKI alert", params: z.object({ alertId: z.string().trim().describe(ALERTS.GET.alertId) @@ -108,6 +112,8 @@ export const registerPkiAlertRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiAlerting], description: "Update PKI alert", params: z.object({ alertId: z.string().trim().describe(ALERTS.UPDATE.alertId) @@ -164,6 +170,8 @@ export const registerPkiAlertRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiAlerting], description: "Delete PKI alert", params: z.object({ alertId: z.string().trim().describe(ALERTS.DELETE.alertId) diff --git a/backend/src/server/routes/v1/pki-collection-router.ts b/backend/src/server/routes/v1/pki-collection-router.ts index 2f2add5c1..92f883b38 100644 --- a/backend/src/server/routes/v1/pki-collection-router.ts +++ b/backend/src/server/routes/v1/pki-collection-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { PkiCollectionItemsSchema, PkiCollectionsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { PKI_COLLECTIONS } from "@app/lib/api-docs"; +import { ApiDocsTags, PKI_COLLECTIONS } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -17,6 +17,8 @@ export const registerPkiCollectionRouter = async (server: FastifyZodProvider) => }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateCollections], description: "Create PKI collection", body: z.object({ projectId: z.string().trim().describe(PKI_COLLECTIONS.CREATE.projectId), @@ -60,6 +62,8 @@ export const registerPkiCollectionRouter = async (server: FastifyZodProvider) => }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateCollections], description: "Get PKI collection", params: z.object({ collectionId: z.string().trim().describe(PKI_COLLECTIONS.GET.collectionId) @@ -100,6 +104,8 @@ export const registerPkiCollectionRouter = async (server: FastifyZodProvider) => }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateCollections], description: "Update PKI collection", params: z.object({ collectionId: z.string().trim().describe(PKI_COLLECTIONS.UPDATE.collectionId) @@ -146,6 +152,8 @@ export const registerPkiCollectionRouter = async (server: FastifyZodProvider) => }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateCollections], description: "Delete PKI collection", params: z.object({ collectionId: z.string().trim().describe(PKI_COLLECTIONS.DELETE.collectionId) @@ -186,6 +194,8 @@ export const registerPkiCollectionRouter = async (server: FastifyZodProvider) => }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateCollections], description: "Get items in PKI collection", params: z.object({ collectionId: z.string().trim().describe(PKI_COLLECTIONS.LIST_ITEMS.collectionId) @@ -247,6 +257,8 @@ export const registerPkiCollectionRouter = async (server: FastifyZodProvider) => }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateCollections], description: "Add item to PKI collection", params: z.object({ collectionId: z.string().trim().describe(PKI_COLLECTIONS.ADD_ITEM.collectionId) @@ -298,6 +310,8 @@ export const registerPkiCollectionRouter = async (server: FastifyZodProvider) => }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateCollections], description: "Remove item from PKI collection", params: z.object({ collectionId: z.string().trim().describe(PKI_COLLECTIONS.DELETE_ITEM.collectionId), diff --git a/backend/src/server/routes/v1/project-env-router.ts b/backend/src/server/routes/v1/project-env-router.ts index 705016696..9a136e160 100644 --- a/backend/src/server/routes/v1/project-env-router.ts +++ b/backend/src/server/routes/v1/project-env-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { ProjectEnvironmentsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { ENVIRONMENTS } from "@app/lib/api-docs"; +import { ApiDocsTags, ENVIRONMENTS } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { slugSchema } from "@app/server/lib/schemas"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -13,9 +13,11 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { method: "GET", url: "/:workspaceId/environments/:envId", config: { - rateLimit: writeLimit + rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Environments], description: "Get Environment", security: [ { @@ -65,6 +67,8 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Environments], description: "Get Environment by ID", security: [ { @@ -112,6 +116,8 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Environments], description: "Create environment", security: [ { @@ -171,6 +177,8 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Environments], description: "Update environment", security: [ { @@ -237,6 +245,8 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Environments], description: "Delete environment", security: [ { diff --git a/backend/src/server/routes/v1/project-membership-router.ts b/backend/src/server/routes/v1/project-membership-router.ts index b5a4a8677..cd3734efc 100644 --- a/backend/src/server/routes/v1/project-membership-router.ts +++ b/backend/src/server/routes/v1/project-membership-router.ts @@ -8,7 +8,7 @@ import { UsersSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { PROJECT_USERS } from "@app/lib/api-docs"; +import { ApiDocsTags, PROJECT_USERS } from "@app/lib/api-docs"; import { ms } from "@app/lib/ms"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -23,6 +23,8 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectUsers], description: "Return project user memberships", security: [ { @@ -141,6 +143,8 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectUsers], description: "Return project user memberships", security: [ { @@ -255,6 +259,8 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectUsers], description: "Update project user membership", security: [ { diff --git a/backend/src/server/routes/v1/project-router.ts b/backend/src/server/routes/v1/project-router.ts index 407bdef1f..19423901b 100644 --- a/backend/src/server/routes/v1/project-router.ts +++ b/backend/src/server/routes/v1/project-router.ts @@ -13,7 +13,7 @@ import { UsersSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { PROJECTS } from "@app/lib/api-docs"; +import { ApiDocsTags, PROJECTS } from "@app/lib/api-docs"; import { CharacterType, characterValidator } from "@app/lib/validator/validate-string"; import { re2Validator } from "@app/lib/zod"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; @@ -177,6 +177,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Projects], description: "Get project", security: [ { @@ -215,6 +217,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Projects], description: "Delete project", security: [ { @@ -290,6 +294,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Projects], description: "Update project", security: [ { @@ -513,6 +519,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Integrations], description: "List integrations for a project.", security: [ { @@ -556,6 +564,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Integrations], description: "List integration auth objects for a workspace.", security: [ { diff --git a/backend/src/server/routes/v1/secret-folder-router.ts b/backend/src/server/routes/v1/secret-folder-router.ts index dbfa715ea..b307347b8 100644 --- a/backend/src/server/routes/v1/secret-folder-router.ts +++ b/backend/src/server/routes/v1/secret-folder-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { SecretFoldersSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { FOLDERS } from "@app/lib/api-docs"; +import { ApiDocsTags, FOLDERS } from "@app/lib/api-docs"; import { prefixWithSlash, removeTrailingSlash } from "@app/lib/fn"; import { isValidFolderName } from "@app/lib/validator"; import { readLimit, secretsLimit } from "@app/server/config/rateLimiter"; @@ -19,6 +19,8 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Folders], description: "Create folders", security: [ { @@ -98,6 +100,8 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Folders], description: "Update folder", security: [ { @@ -181,6 +185,8 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Folders], description: "Update folders by batch", security: [ { @@ -259,6 +265,8 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Folders], description: "Delete a folder", security: [ { @@ -332,6 +340,8 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Folders], description: "Get folders", security: [ { @@ -390,6 +400,8 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Folders], description: "Get folder by id", security: [ { diff --git a/backend/src/server/routes/v1/secret-import-router.ts b/backend/src/server/routes/v1/secret-import-router.ts index aa6efdf36..fca11f8a0 100644 --- a/backend/src/server/routes/v1/secret-import-router.ts +++ b/backend/src/server/routes/v1/secret-import-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { SecretImportsSchema, SecretsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { SECRET_IMPORTS } from "@app/lib/api-docs"; +import { ApiDocsTags, SECRET_IMPORTS } from "@app/lib/api-docs"; import { removeTrailingSlash } from "@app/lib/fn"; import { readLimit, secretsLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -18,6 +18,8 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretImports], description: "Create secret imports", security: [ { @@ -83,6 +85,8 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretImports], description: "Update secret imports", security: [ { @@ -157,6 +161,8 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretImports], description: "Delete secret imports", security: [ { @@ -263,6 +269,8 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretImports], description: "Get secret imports", security: [ { @@ -319,6 +327,8 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretImports], description: "Get single secret import", security: [ { @@ -421,6 +431,8 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretImports], querystring: z.object({ workspaceId: z.string().trim(), environment: z.string().trim(), diff --git a/backend/src/server/routes/v1/secret-sync-routers/secret-sync-endpoints.ts b/backend/src/server/routes/v1/secret-sync-routers/secret-sync-endpoints.ts index 31826f86f..6ab9b5939 100644 --- a/backend/src/server/routes/v1/secret-sync-routers/secret-sync-endpoints.ts +++ b/backend/src/server/routes/v1/secret-sync-routers/secret-sync-endpoints.ts @@ -1,7 +1,7 @@ import { z } from "zod"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { SecretSyncs } from "@app/lib/api-docs"; +import { ApiDocsTags, SecretSyncs } from "@app/lib/api-docs"; import { startsWithVowel } from "@app/lib/fn"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -51,6 +51,8 @@ export const registerSyncSecretsEndpoints = { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretSyncs], description: "List the available Secret Sync Options.", response: { 200: z.object({ @@ -86,6 +88,8 @@ export const registerSecretSyncRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SecretSyncs], description: "List all the Secret Syncs for the specified project.", querystring: z.object({ projectId: z.string().trim().min(1, "Project ID required").describe(SecretSyncs.LIST().projectId) diff --git a/backend/src/server/routes/v1/secret-tag-router.ts b/backend/src/server/routes/v1/secret-tag-router.ts index ed9837084..01ba783fe 100644 --- a/backend/src/server/routes/v1/secret-tag-router.ts +++ b/backend/src/server/routes/v1/secret-tag-router.ts @@ -1,7 +1,7 @@ import { z } from "zod"; import { SecretTagsSchema } from "@app/db/schemas"; -import { SECRET_TAGS } from "@app/lib/api-docs"; +import { ApiDocsTags, SECRET_TAGS } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { slugSchema } from "@app/server/lib/schemas"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -15,6 +15,8 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Folders], params: z.object({ projectId: z.string().trim().describe(SECRET_TAGS.LIST.projectId) }), @@ -44,6 +46,8 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Folders], params: z.object({ projectId: z.string().trim().describe(SECRET_TAGS.GET_TAG_BY_ID.projectId), tagId: z.string().trim().describe(SECRET_TAGS.GET_TAG_BY_ID.tagId) @@ -75,6 +79,8 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Folders], params: z.object({ projectId: z.string().trim().describe(SECRET_TAGS.GET_TAG_BY_SLUG.projectId), tagSlug: z.string().trim().describe(SECRET_TAGS.GET_TAG_BY_SLUG.tagSlug) @@ -107,6 +113,8 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Folders], params: z.object({ projectId: z.string().trim().describe(SECRET_TAGS.CREATE.projectId) }), @@ -141,6 +149,8 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Folders], params: z.object({ projectId: z.string().trim().describe(SECRET_TAGS.UPDATE.projectId), tagId: z.string().trim().describe(SECRET_TAGS.UPDATE.tagId) @@ -176,6 +186,8 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Folders], params: z.object({ projectId: z.string().trim().describe(SECRET_TAGS.DELETE.projectId), tagId: z.string().trim().describe(SECRET_TAGS.DELETE.tagId) diff --git a/backend/src/server/routes/v2/group-project-router.ts b/backend/src/server/routes/v2/group-project-router.ts index 47456e622..5a081a3d9 100644 --- a/backend/src/server/routes/v2/group-project-router.ts +++ b/backend/src/server/routes/v2/group-project-router.ts @@ -6,7 +6,7 @@ import { ProjectMembershipRole, ProjectUserMembershipRolesSchema } from "@app/db/schemas"; -import { PROJECTS } from "@app/lib/api-docs"; +import { ApiDocsTags, PROJECTS } from "@app/lib/api-docs"; import { ms } from "@app/lib/ms"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -22,6 +22,8 @@ export const registerGroupProjectRouter = async (server: FastifyZodProvider) => rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectGroups], description: "Add group to project", security: [ { @@ -88,6 +90,8 @@ export const registerGroupProjectRouter = async (server: FastifyZodProvider) => url: "/:projectId/groups/:groupId", onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.ProjectGroups], description: "Update group in project", security: [ { @@ -147,6 +151,8 @@ export const registerGroupProjectRouter = async (server: FastifyZodProvider) => rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectGroups], description: "Remove group from project", security: [ { @@ -185,6 +191,8 @@ export const registerGroupProjectRouter = async (server: FastifyZodProvider) => rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectGroups], description: "Return list of groups in project", security: [ { @@ -243,6 +251,8 @@ export const registerGroupProjectRouter = async (server: FastifyZodProvider) => rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectGroups], description: "Return project group", security: [ { diff --git a/backend/src/server/routes/v2/identity-org-router.ts b/backend/src/server/routes/v2/identity-org-router.ts index 52940eb44..8680a2dca 100644 --- a/backend/src/server/routes/v2/identity-org-router.ts +++ b/backend/src/server/routes/v2/identity-org-router.ts @@ -1,7 +1,7 @@ import { z } from "zod"; import { IdentitiesSchema, IdentityOrgMembershipsSchema, OrgRolesSchema } from "@app/db/schemas"; -import { ORGANIZATIONS } from "@app/lib/api-docs"; +import { ApiDocsTags, ORGANIZATIONS } from "@app/lib/api-docs"; import { OrderByDirection } from "@app/lib/types"; import { readLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -17,6 +17,8 @@ export const registerIdentityOrgRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.Organizations], description: "Return organization identity memberships", security: [ { diff --git a/backend/src/server/routes/v2/identity-project-router.ts b/backend/src/server/routes/v2/identity-project-router.ts index 4205d9326..9de7ed1aa 100644 --- a/backend/src/server/routes/v2/identity-project-router.ts +++ b/backend/src/server/routes/v2/identity-project-router.ts @@ -6,7 +6,7 @@ import { ProjectMembershipRole, ProjectUserMembershipRolesSchema } from "@app/db/schemas"; -import { ORGANIZATIONS, PROJECT_IDENTITIES } from "@app/lib/api-docs"; +import { ApiDocsTags, ORGANIZATIONS, PROJECT_IDENTITIES } from "@app/lib/api-docs"; import { BadRequestError } from "@app/lib/errors"; import { ms } from "@app/lib/ms"; import { OrderByDirection } from "@app/lib/types"; @@ -27,6 +27,8 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.ProjectIdentities], description: "Create project identity membership", security: [ { @@ -101,6 +103,8 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.ProjectIdentities], description: "Update project identity memberships", security: [ { @@ -170,6 +174,8 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.ProjectIdentities], description: "Delete project identity memberships", security: [ { @@ -207,6 +213,8 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.ProjectIdentities], description: "Return project identity memberships", security: [ { @@ -300,6 +308,8 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.ProjectIdentities], description: "Return project identity membership", security: [ { @@ -360,6 +370,8 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider) }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.ProjectIdentities], params: z.object({ identityMembershipId: z.string().trim() }), diff --git a/backend/src/server/routes/v2/organization-router.ts b/backend/src/server/routes/v2/organization-router.ts index 90b500a5a..504359726 100644 --- a/backend/src/server/routes/v2/organization-router.ts +++ b/backend/src/server/routes/v2/organization-router.ts @@ -8,7 +8,7 @@ import { UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas"; -import { ORGANIZATIONS } from "@app/lib/api-docs"; +import { ApiDocsTags, ORGANIZATIONS } from "@app/lib/api-docs"; import { getConfig } from "@app/lib/config/env"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { GenericResourceNameSchema } from "@app/server/lib/schemas"; @@ -24,6 +24,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Organizations], description: "Return organization user memberships", security: [ { @@ -72,6 +74,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Organizations], description: "Return projects in organization that user is apart of", security: [ { @@ -179,6 +183,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Organizations], description: "Update organization user memberships", security: [ { @@ -229,6 +235,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Organizations], description: "Delete organization user memberships", security: [ { diff --git a/backend/src/server/routes/v2/project-membership-router.ts b/backend/src/server/routes/v2/project-membership-router.ts index 0c3ceb01e..a1a1cfc96 100644 --- a/backend/src/server/routes/v2/project-membership-router.ts +++ b/backend/src/server/routes/v2/project-membership-router.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { OrgMembershipRole, ProjectMembershipRole, ProjectMembershipsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; -import { PROJECT_USERS } from "@app/lib/api-docs"; +import { ApiDocsTags, PROJECT_USERS } from "@app/lib/api-docs"; import { writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -15,6 +15,8 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectUsers], description: "Invite members to project", security: [ { @@ -78,6 +80,8 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.ProjectUsers], description: "Remove members from project", security: [ { diff --git a/backend/src/server/routes/v2/project-router.ts b/backend/src/server/routes/v2/project-router.ts index c8f68a926..f7540591e 100644 --- a/backend/src/server/routes/v2/project-router.ts +++ b/backend/src/server/routes/v2/project-router.ts @@ -14,7 +14,7 @@ import { sanitizedSshCa } from "@app/ee/services/ssh/ssh-certificate-authority-s import { sanitizedSshCertificate } from "@app/ee/services/ssh-certificate/ssh-certificate-schema"; import { sanitizedSshCertificateTemplate } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-schema"; import { loginMappingSchema, sanitizedSshHost } from "@app/ee/services/ssh-host/ssh-host-schema"; -import { PROJECTS } from "@app/lib/api-docs"; +import { ApiDocsTags, PROJECTS } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { slugSchema } from "@app/server/lib/schemas"; import { getTelemetryDistinctId } from "@app/server/lib/telemetry"; @@ -29,7 +29,8 @@ import { SanitizedProjectSchema } from "../sanitizedSchemas"; const projectWithEnv = SanitizedProjectSchema.extend({ _id: z.string(), - environments: z.object({ name: z.string(), slug: z.string(), id: z.string() }).array() + environments: z.object({ name: z.string(), slug: z.string(), id: z.string() }).array(), + kmsSecretManagerKeyId: z.string().nullable().optional() }); export const registerProjectRouter = async (server: FastifyZodProvider) => { @@ -150,6 +151,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Projects], description: "Create a new project", security: [ { @@ -224,6 +227,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Projects], description: "Delete project", security: [ { @@ -342,6 +347,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificateAuthorities], params: z.object({ slug: slugSchema({ min: 5, max: 36 }).describe(PROJECTS.LIST_CAS.slug) }), @@ -383,6 +390,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.PkiCertificates], params: z.object({ slug: slugSchema({ min: 5, max: 36 }).describe(PROJECTS.LIST_CERTIFICATES.slug) }), @@ -551,6 +560,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SshCertificateTemplates], params: z.object({ projectId: z.string().trim().describe(PROJECTS.LIST_SSH_CERTIFICATE_TEMPLATES.projectId) }), @@ -581,6 +592,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { rateLimit: readLimit }, schema: { + hide: false, + tags: [ApiDocsTags.SshCertificateAuthorities], params: z.object({ projectId: z.string().trim().describe(PROJECTS.LIST_SSH_CAS.projectId) }), diff --git a/backend/src/server/routes/v2/service-token-router.ts b/backend/src/server/routes/v2/service-token-router.ts index fb10f17db..aa6165d90 100644 --- a/backend/src/server/routes/v2/service-token-router.ts +++ b/backend/src/server/routes/v2/service-token-router.ts @@ -2,6 +2,7 @@ import { z } from "zod"; import { ServiceTokensSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { ApiDocsTags } from "@app/lib/api-docs"; import { removeTrailingSlash } from "@app/lib/fn"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -25,6 +26,8 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) => }, onRequest: verifyAuth([AuthMode.SERVICE_TOKEN]), schema: { + hide: false, + tags: [ApiDocsTags.ServiceTokens], description: "Return Infisical Token data", security: [ { diff --git a/backend/src/server/routes/v3/secret-router.ts b/backend/src/server/routes/v3/secret-router.ts index 0f53b777a..40aed624b 100644 --- a/backend/src/server/routes/v3/secret-router.ts +++ b/backend/src/server/routes/v3/secret-router.ts @@ -3,7 +3,7 @@ import { z } from "zod"; import { SecretApprovalRequestsSchema, SecretsSchema, SecretType, ServiceTokenScopes } from "@app/db/schemas"; import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types"; -import { RAW_SECRETS, SECRETS } from "@app/lib/api-docs"; +import { ApiDocsTags, RAW_SECRETS, SECRETS } from "@app/lib/api-docs"; import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { removeTrailingSlash } from "@app/lib/fn"; import { secretsLimit, writeLimit } from "@app/server/config/rateLimiter"; @@ -48,6 +48,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Secrets], description: "Attach tags to a secret", security: [ { @@ -103,6 +105,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { rateLimit: writeLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Secrets], description: "Detach tags from a secret", security: [ { @@ -158,6 +162,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Secrets], description: "List secrets", security: [ { @@ -355,6 +361,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Secrets], params: z.object({ secretId: z.string() }), @@ -390,6 +398,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Secrets], description: "Get a secret by name", security: [ { @@ -496,6 +506,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Secrets], description: "Create secret", security: [ { @@ -609,6 +621,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Secrets], description: "Update secret", security: [ { @@ -729,6 +743,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Secrets], description: "Delete secret", security: [ { @@ -1486,6 +1502,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Secrets], body: z.object({ projectSlug: z.string().trim(), sourceEnvironment: z.string().trim(), @@ -1911,6 +1929,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Secrets], description: "Create many secrets", security: [ { @@ -2017,6 +2037,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Secrets], description: "Update many secrets", security: [ { @@ -2170,6 +2192,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Secrets], description: "Delete many secrets", security: [ { @@ -2266,6 +2290,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { rateLimit: secretsLimit }, schema: { + hide: false, + tags: [ApiDocsTags.Secrets], description: "Get secret reference tree", security: [ { diff --git a/backend/src/services/auth/auth-login-service.ts b/backend/src/services/auth/auth-login-service.ts index 0e0f999dd..e576d6768 100644 --- a/backend/src/services/auth/auth-login-service.ts +++ b/backend/src/services/auth/auth-login-service.ts @@ -3,6 +3,8 @@ import jwt from "jsonwebtoken"; import { Knex } from "knex"; import { OrgMembershipRole, TUsers, UserDeviceSchema } from "@app/db/schemas"; +import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service"; +import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { isAuthMethodSaml } from "@app/ee/services/permission/permission-fns"; import { getConfig } from "@app/lib/config/env"; import { request } from "@app/lib/config/request"; @@ -11,6 +13,7 @@ import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption"; import { getUserPrivateKey } from "@app/lib/crypto/srp"; import { BadRequestError, DatabaseError, ForbiddenRequestError, UnauthorizedError } from "@app/lib/errors"; import { logger } from "@app/lib/logger"; +import { getUserAgentType } from "@app/server/plugins/audit-log"; import { getServerCfg } from "@app/services/super-admin/super-admin-service"; import { TAuthTokenServiceFactory } from "../auth-token/auth-token-service"; @@ -28,7 +31,15 @@ import { TOauthTokenExchangeDTO, TVerifyMfaTokenDTO } from "./auth-login-type"; -import { AuthMethod, AuthModeJwtTokenPayload, AuthModeMfaJwtTokenPayload, AuthTokenType, MfaMethod } from "./auth-type"; +import { + ActorType, + AuthMethod, + AuthModeJwtTokenPayload, + AuthModeMfaJwtTokenPayload, + AuthTokenType, + MfaMethod +} from "./auth-type"; +import { removeTrailingSlash } from "@app/lib/fn"; type TAuthLoginServiceFactoryDep = { userDAL: TUserDALFactory; @@ -36,6 +47,7 @@ type TAuthLoginServiceFactoryDep = { tokenService: TAuthTokenServiceFactory; smtpService: TSmtpService; totpService: Pick; + auditLogService: Pick; }; export type TAuthLoginFactory = ReturnType; @@ -44,7 +56,8 @@ export const authLoginServiceFactory = ({ tokenService, smtpService, orgDAL, - totpService + totpService, + auditLogService }: TAuthLoginServiceFactoryDep) => { /* * Private @@ -412,6 +425,55 @@ export const authLoginServiceFactory = ({ mfaMethod: decodedToken.mfaMethod }); + // In the event of this being a break-glass request (non-saml / non-oidc, when either is enforced) + if ( + selectedOrg.authEnforced && + selectedOrg.bypassOrgAuthEnabled && + !isAuthMethodSaml(decodedToken.authMethod) && + decodedToken.authMethod !== AuthMethod.OIDC + ) { + await auditLogService.createAuditLog({ + orgId: organizationId, + ipAddress, + userAgent, + userAgentType: getUserAgentType(userAgent), + actor: { + type: ActorType.USER, + metadata: { + email: user.email, + userId: user.id, + username: user.username + } + }, + event: { + type: EventType.ORG_ADMIN_BYPASS_SSO, + metadata: {} + } + }); + + // Notify all admins via email (besides the actor) + const orgAdmins = await orgDAL.findOrgMembersByRole(organizationId, OrgMembershipRole.Admin); + const adminEmails = orgAdmins + .filter((admin) => admin.user.id !== user.id) + .map((admin) => admin.user.email) + .filter(Boolean) as string[]; + + if (adminEmails.length > 0) { + await smtpService.sendMail({ + recipients: adminEmails, + subjectLine: "Security Alert: Admin SSO Bypass", + substitutions: { + email: user.email, + timestamp: new Date().toISOString(), + ip: ipAddress, + userAgent, + siteUrl: removeTrailingSlash(cfg.SITE_URL || "https://app.infisical.com") + }, + template: SmtpTemplates.OrgAdminBreakglassAccess + }); + } + } + return { ...tokens, isMfaEnabled: false diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts index 0849a7523..fe7b24783 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts @@ -68,18 +68,15 @@ const awsRegionFromHeader = (authorizationHeader: string): string | null => { return null; }; - - -function isValidAwsRegion(region: (string | null)): boolean { - const validRegionPattern = new RE2('^[a-z0-9-]+$'); - if (typeof region !== 'string' || region.length === 0 || region.length > 20) { +function isValidAwsRegion(region: string | null): boolean { + const validRegionPattern = new RE2("^[a-z0-9-]+$"); + if (typeof region !== "string" || region.length === 0 || region.length > 20) { return false; } - + return validRegionPattern.test(region); } - export const identityAwsAuthServiceFactory = ({ identityAccessTokenDAL, identityAwsAuthDAL, @@ -100,7 +97,7 @@ export const identityAwsAuthServiceFactory = ({ const region = headers.Authorization ? awsRegionFromHeader(headers.Authorization) : null; if (!isValidAwsRegion(region)) { - throw new BadRequestError({message: "Invalid AWS region"}); + throw new BadRequestError({ message: "Invalid AWS region" }); } const url = region ? `https://sts.${region}.amazonaws.com` : identityAwsAuth.stsEndpoint; diff --git a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts index a5e036d35..9c0e8d2dd 100644 --- a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts +++ b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts @@ -435,12 +435,16 @@ export const identityKubernetesAuthServiceFactory = ({ const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId }); if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` }); + const identityKubernetesAuth = await identityKubernetesAuthDAL.findOne({ identityId }); + if (!identityKubernetesAuth) { + throw new NotFoundError({ message: `Failed to find Kubernetes Auth for identity with ID ${identityId}` }); + } + if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.KUBERNETES_AUTH)) { throw new BadRequestError({ message: "The identity does not have Kubernetes Auth attached" }); } - const identityKubernetesAuth = await identityKubernetesAuthDAL.findOne({ identityId }); const { permission } = await permissionService.getOrgPermission( actor, diff --git a/backend/src/services/integration-auth/integration-delete-secret.ts b/backend/src/services/integration-auth/integration-delete-secret.ts index 18406f29a..f77becb02 100644 --- a/backend/src/services/integration-auth/integration-delete-secret.ts +++ b/backend/src/services/integration-auth/integration-delete-secret.ts @@ -50,7 +50,7 @@ const getIntegrationSecretsV2 = async ( } // process secrets in current folder - const secrets = await secretV2BridgeDAL.findByFolderId({ folderId: dto.folderId, projectId: dto.projectId }); + const secrets = await secretV2BridgeDAL.findByFolderId({ folderId: dto.folderId }); secrets.forEach((secret) => { const secretKey = secret.key; @@ -63,7 +63,6 @@ const getIntegrationSecretsV2 = async ( // if no imports then return secrets in the current folder if (!secretImports.length) return content; const importedSecrets = await fnSecretsV2FromImports({ - projectId: dto.projectId, decryptor: dto.decryptor, folderDAL, secretDAL: secretV2BridgeDAL, diff --git a/backend/src/services/kms/kms-service.ts b/backend/src/services/kms/kms-service.ts index 07ed90bef..8bfa50b64 100644 --- a/backend/src/services/kms/kms-service.ts +++ b/backend/src/services/kms/kms-service.ts @@ -787,13 +787,19 @@ export const kmsServiceFactory = ({ return projectDataKey; } } + } catch (error) { + logger.error( + error, + `getProjectSecretManagerKmsDataKey: Failed to get project data key for [projectId=${projectId}]` + ); + throw error; } finally { await lock?.release(); } } if (!project.kmsSecretManagerEncryptedDataKey) { - throw new Error("Missing project data key"); + throw new BadRequestError({ message: "Missing project data key" }); } const kmsDecryptor = await decryptWithKmsKey({ diff --git a/backend/src/services/org/org-dal.ts b/backend/src/services/org/org-dal.ts index 02bf58321..54b0e1b0f 100644 --- a/backend/src/services/org/org-dal.ts +++ b/backend/src/services/org/org-dal.ts @@ -2,6 +2,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; import { + OrgMembershipRole, TableName, TOrganizations, TOrganizationsInsert, @@ -216,9 +217,8 @@ export const orgDALFactory = (db: TDbClient) => { const findOrgMembersByUsername = async (orgId: string, usernames: string[], tx?: Knex) => { try { - const conn = tx || db; + const conn = tx || db.replicaNode(); const members = await conn(TableName.OrgMembership) - // .replicaNode()(TableName.OrgMembership) .where(`${TableName.OrgMembership}.orgId`, orgId) .join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`) .leftJoin( @@ -251,6 +251,43 @@ export const orgDALFactory = (db: TDbClient) => { } }; + const findOrgMembersByRole = async (orgId: string, role: OrgMembershipRole, tx?: Knex) => { + try { + const conn = tx || db.replicaNode(); + const members = await conn(TableName.OrgMembership) + .where(`${TableName.OrgMembership}.orgId`, orgId) + .where(`${TableName.OrgMembership}.role`, role) + .join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`) + .leftJoin( + TableName.UserEncryptionKey, + `${TableName.UserEncryptionKey}.userId`, + `${TableName.Users}.id` + ) + .select( + conn.ref("id").withSchema(TableName.OrgMembership), + conn.ref("inviteEmail").withSchema(TableName.OrgMembership), + conn.ref("orgId").withSchema(TableName.OrgMembership), + conn.ref("role").withSchema(TableName.OrgMembership), + conn.ref("roleId").withSchema(TableName.OrgMembership), + conn.ref("status").withSchema(TableName.OrgMembership), + conn.ref("username").withSchema(TableName.Users), + conn.ref("email").withSchema(TableName.Users), + conn.ref("firstName").withSchema(TableName.Users), + conn.ref("lastName").withSchema(TableName.Users), + conn.ref("id").withSchema(TableName.Users).as("userId"), + conn.ref("publicKey").withSchema(TableName.UserEncryptionKey) + ) + .where({ isGhost: false }); + + return members.map(({ username, email, firstName, lastName, userId, publicKey, ...data }) => ({ + ...data, + user: { username, email, firstName, lastName, id: userId, publicKey } + })); + } catch (error) { + throw new DatabaseError({ error, name: "Find org members by role" }); + } + }; + const findOrgGhostUser = async (orgId: string) => { try { const member = await db @@ -472,6 +509,7 @@ export const orgDALFactory = (db: TDbClient) => { findAllOrgsByUserId, ghostUserExists, findOrgMembersByUsername, + findOrgMembersByRole, findOrgGhostUser, create, updateById, diff --git a/backend/src/services/secret-import/secret-import-fns.ts b/backend/src/services/secret-import/secret-import-fns.ts index 2056d5a2c..c68033911 100644 --- a/backend/src/services/secret-import/secret-import-fns.ts +++ b/backend/src/services/secret-import/secret-import-fns.ts @@ -159,8 +159,7 @@ export const fnSecretsV2FromImports = async ({ decryptor, expandSecretReferences, hasSecretAccess, - viewSecretValue, - projectId + viewSecretValue }: { secretImports: (Omit & { importEnv: { id: string; slug: string; name: string }; @@ -177,7 +176,6 @@ export const fnSecretsV2FromImports = async ({ environment: string; }) => Promise; hasSecretAccess: (environment: string, secretPath: string, secretName: string, secretTagSlugs: string[]) => boolean; - projectId: string; }) => { const cyclicDetector = new Set(); const stack: { @@ -209,7 +207,10 @@ export const fnSecretsV2FromImports = async ({ ); if (!importedFolders.length) continue; - const importedFolderIds = importedFolders.map((el) => el?.id) as string[]; + const importedFolderIds = importedFolders.filter(Boolean).map((el) => el?.id) as string[]; + + if (!importedFolderIds.length) continue; + const importedFolderGroupBySourceImport = groupBy(importedFolders, (i) => `${i?.envId}-${i?.path}`); const importedSecrets = await secretDAL.find( @@ -218,8 +219,7 @@ export const fnSecretsV2FromImports = async ({ type: SecretType.Shared }, { - sort: [["id", "asc"]], - useCache: { projectId } + sort: [["id", "asc"]] } ); const importedSecretsGroupByFolderId = groupBy(importedSecrets, (i) => i.folderId); diff --git a/backend/src/services/secret-import/secret-import-service.ts b/backend/src/services/secret-import/secret-import-service.ts index d21003b10..2015516f5 100644 --- a/backend/src/services/secret-import/secret-import-service.ts +++ b/backend/src/services/secret-import/secret-import-service.ts @@ -698,7 +698,6 @@ export const secretImportServiceFactory = ({ projectId }); const importedSecrets = await fnSecretsV2FromImports({ - projectId, secretImports, folderDAL, viewSecretValue: true, diff --git a/backend/src/services/secret-sync/secret-sync-queue.ts b/backend/src/services/secret-sync/secret-sync-queue.ts index 9f4e283a9..3177b68b1 100644 --- a/backend/src/services/secret-sync/secret-sync-queue.ts +++ b/backend/src/services/secret-sync/secret-sync-queue.ts @@ -214,7 +214,7 @@ export const secretSyncQueueFactory = ({ canExpandValue: () => true }); - const secrets = await secretV2BridgeDAL.findByFolderId({ folderId, projectId }); + const secrets = await secretV2BridgeDAL.findByFolderId({ folderId }); await Promise.allSettled( secrets.map(async (secret) => { @@ -244,7 +244,6 @@ export const secretSyncQueueFactory = ({ if (secretImports.length) { const importedSecrets = await fnSecretsV2FromImports({ - projectId, decryptor: decryptSecretValue, folderDAL, secretDAL: secretV2BridgeDAL, diff --git a/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts b/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts index a9c909899..05fc7cd35 100644 --- a/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts +++ b/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts @@ -1,3 +1,4 @@ +import { MongoAbility } from "@casl/ability"; import { Knex } from "knex"; import { validate as uuidValidate } from "uuid"; @@ -15,46 +16,29 @@ import { TFindFilter, TFindOpt } from "@app/lib/knex"; -import { BufferKeysToString, OrderByDirection } from "@app/lib/types"; +import { OrderByDirection } from "@app/lib/types"; import { SecretsOrderBy } from "@app/services/secret/secret-types"; -import type { TFindSecretsByFolderIdsFilter } from "@app/services/secret-v2-bridge/secret-v2-bridge-types"; +import type { + TFindSecretsByFolderIdsFilter, + TGetSecretsDTO +} from "@app/services/secret-v2-bridge/secret-v2-bridge-types"; -export const SecretDalCacheKeys = { +export const SecretServiceCacheKeys = { get productKey() { const { INFISICAL_PLATFORM_VERSION } = getConfig(); return `${ProjectType.SecretManager}:${INFISICAL_PLATFORM_VERSION || 0}`; }, getSecretDalVersion: (projectId: string) => { - return `${SecretDalCacheKeys.productKey}:${projectId}:${TableName.SecretV2}-dal-version`; + return `${SecretServiceCacheKeys.productKey}:${projectId}:${TableName.SecretV2}-dal-version`; }, - findByFolderIds: ( + getSecretsOfServiceLayer: ( projectId: string, version: number, - { useCache, tx, ...cacheKey }: Parameters[0] + dto: TGetSecretsDTO & { permissionRules: MongoAbility["rules"] } ) => { - return `${SecretDalCacheKeys.productKey}:${projectId}:${ + return `${SecretServiceCacheKeys.productKey}:${projectId}:${ TableName.SecretV2 - }-dal:v${version}:find-by-folder-ids:${generateCacheKeyFromData(cacheKey)}`; - }, - findByFolderId: ( - projectId: string, - version: number, - { useCache, tx, ...cacheKey }: Parameters[0] - ) => { - return `${SecretDalCacheKeys.productKey}:${projectId}:${ - TableName.SecretV2 - }-dal:v${version}:find-by-folder-id:${generateCacheKeyFromData(cacheKey)}`; - }, - find: (projectId: string, version: number, ...args: Parameters) => { - const [filter, opts] = args; - delete opts?.tx; - delete opts?.useCache; - return `${SecretDalCacheKeys.productKey}:${projectId}:${ - TableName.SecretV2 - }-dal:v${version}:find:${generateCacheKeyFromData({ - filter, - opts - })}`; + }-dal:v${version}:get-secrets-service-layer:${dto.actorId}-${generateCacheKeyFromData(dto)}`; } }; @@ -64,14 +48,14 @@ interface TSecretV2DalArg { keyStore: TKeyStoreFactory; } -const SECRET_DAL_TTL = 5 * 60; -const SECRET_DAL_VERSION_TTL = 15 * 60; -const MAX_SECRET_CACHE_BYTES = 25 * 1024 * 1024; +export const SECRET_DAL_TTL = 5 * 60; +export const SECRET_DAL_VERSION_TTL = 15 * 60; +export const MAX_SECRET_CACHE_BYTES = 25 * 1024 * 1024; export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { const secretOrm = ormify(db, TableName.SecretV2); const invalidateSecretCacheByProjectId = async (projectId: string) => { - const secretDalVersionKey = SecretDalCacheKeys.getSecretDalVersion(projectId); + const secretDalVersionKey = SecretServiceCacheKeys.getSecretDalVersion(projectId); await keyStore.incrementBy(secretDalVersionKey, 1); await keyStore.setExpiry(secretDalVersionKey, SECRET_DAL_VERSION_TTL); }; @@ -128,35 +112,9 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { } }; - const find = async ( - filter: TFindFilter, - opts: TFindOpt & { useCache?: { projectId: string } } = {} - ) => { - const { offset, limit, sort, tx, useCache } = opts; + const find = async (filter: TFindFilter, opts: TFindOpt = {}) => { + const { offset, limit, sort, tx } = opts; try { - let secretDalVersion = 0; - if (useCache) { - const cachedSecretDalVersion = await keyStore.getItem( - SecretDalCacheKeys.getSecretDalVersion(useCache.projectId) - ); - secretDalVersion = Number(cachedSecretDalVersion || 0); - const cacheKey = SecretDalCacheKeys.find(useCache.projectId, secretDalVersion, filter, opts); - const cachedSecrets = await keyStore.getItem(cacheKey); - if (cachedSecrets) { - await keyStore.setExpiry(cacheKey, SECRET_DAL_TTL); - - const unsanitizedSecrets = JSON.parse(cachedSecrets) as BufferKeysToString<(typeof data)[number]>[]; - const sanitizedSecrets = unsanitizedSecrets.map((el) => { - const encryptedValue = el.encryptedValue ? Buffer.from(el.encryptedValue, "base64") : null; - const encryptedComment = el.encryptedComment ? Buffer.from(el.encryptedComment, "base64") : null; - const createdAt = new Date(el.createdAt); - const updatedAt = new Date(el.updatedAt); - return { ...el, encryptedComment, encryptedValue, createdAt, updatedAt }; - }); - return sanitizedSecrets; - } - } - const query = (tx || db)(TableName.SecretV2) // eslint-disable-next-line @typescript-eslint/no-misused-promises .where(buildFindFilter(filter)) @@ -225,22 +183,6 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { ] }); - if (useCache) { - const cachedSecrets = data.map((el) => { - const encryptedValue = el.encryptedValue ? el.encryptedValue.toString("base64") : null; - const encryptedComment = el.encryptedComment ? el.encryptedComment.toString("base64") : null; - return { ...el, encryptedValue, encryptedComment }; - }); - const cache = JSON.stringify(cachedSecrets); - if (Buffer.byteLength(cache, "utf8") < MAX_SECRET_CACHE_BYTES) { - await keyStore.setItemWithExpiry( - SecretDalCacheKeys.find(useCache.projectId, secretDalVersion, filter, opts), - SECRET_DAL_TTL, - cache - ); - } - } - return data; } catch (error) { throw new DatabaseError({ error, name: `${TableName.SecretV2}: Find` }); @@ -345,15 +287,9 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { } }; - const findByFolderId = async (dto: { - folderId: string; - userId?: string; - tx?: Knex; - projectId: string; - useCache?: boolean; - }) => { + const findByFolderId = async (dto: { folderId: string; userId?: string; tx?: Knex }) => { try { - const { folderId, tx, projectId } = dto; + const { folderId, tx } = dto; let { userId } = dto; // check if not uui then userId id is null (corner case because service token's ID is not UUI in effort to keep backwards compatibility from mongo if (userId && !uuidValidate(userId)) { @@ -361,27 +297,6 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { userId = undefined; } - const cachedSecretDalVersion = await keyStore.getItem(SecretDalCacheKeys.getSecretDalVersion(projectId)); - const secretDalVersion = Number(cachedSecretDalVersion || 0); - - if (dto.useCache) { - const cacheKey = SecretDalCacheKeys.findByFolderId(projectId, secretDalVersion, dto); - const cachedSecrets = await keyStore.getItem(cacheKey); - if (cachedSecrets) { - await keyStore.setExpiry(cacheKey, SECRET_DAL_TTL); - - const unsanitizedSecrets = JSON.parse(cachedSecrets) as BufferKeysToString<(typeof data)[number]>[]; - const sanitizedSecrets = unsanitizedSecrets.map((el) => { - const encryptedValue = el.encryptedValue ? Buffer.from(el.encryptedValue, "base64") : null; - const encryptedComment = el.encryptedComment ? Buffer.from(el.encryptedComment, "base64") : null; - const createdAt = new Date(el.createdAt); - const updatedAt = new Date(el.updatedAt); - return { ...el, encryptedComment, encryptedValue, createdAt, updatedAt }; - }); - return sanitizedSecrets; - } - } - const secs = await (tx || db.replicaNode())(TableName.SecretV2) .where({ folderId }) .where((bd) => { @@ -437,22 +352,6 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { } ] }); - if (dto.useCache) { - const newCachedSecrets = data.map((el) => { - const encryptedValue = el.encryptedValue ? el.encryptedValue.toString("base64") : null; - const encryptedComment = el.encryptedComment ? el.encryptedComment.toString("base64") : null; - return { ...el, encryptedValue, encryptedComment }; - }); - const cache = JSON.stringify(newCachedSecrets); - - if (Buffer.byteLength(cache, "utf8") < MAX_SECRET_CACHE_BYTES) { - await keyStore.setItemWithExpiry( - SecretDalCacheKeys.findByFolderId(projectId, secretDalVersion, dto), - SECRET_DAL_TTL, - cache - ); - } - } return data; } catch (error) { throw new DatabaseError({ error, name: "get all secret" }); @@ -542,11 +441,9 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { folderIds: string[]; userId?: string; tx?: Knex; - projectId: string; filters?: TFindSecretsByFolderIdsFilter; - useCache?: boolean; }) => { - const { folderIds, tx, filters, useCache, projectId } = dto; + const { folderIds, tx, filters } = dto; let { userId } = dto; try { // check if not uui then userId id is null (corner case because service token's ID is not UUI in effort to keep backwards compatibility from mongo) @@ -555,26 +452,6 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { userId = undefined; } - const cachedSecretDalVersion = await keyStore.getItem(SecretDalCacheKeys.getSecretDalVersion(projectId)); - const secretDalVersion = Number(cachedSecretDalVersion || 0); - if (useCache) { - const cacheKey = SecretDalCacheKeys.findByFolderIds(projectId, secretDalVersion, dto); - const cachedSecrets = await keyStore.getItem(cacheKey); - if (cachedSecrets) { - await keyStore.setExpiry(cacheKey, SECRET_DAL_TTL); - - const unsanitizedSecrets = JSON.parse(cachedSecrets) as BufferKeysToString<(typeof data)[number]>[]; - const sanitizedSecrets = unsanitizedSecrets.map((el) => { - const encryptedValue = el.encryptedValue ? Buffer.from(el.encryptedValue, "base64") : null; - const encryptedComment = el.encryptedComment ? Buffer.from(el.encryptedComment, "base64") : null; - const createdAt = new Date(el.createdAt); - const updatedAt = new Date(el.updatedAt); - return { ...el, encryptedComment, encryptedValue, createdAt, updatedAt }; - }); - return sanitizedSecrets; - } - } - const query = (tx || db.replicaNode())(TableName.SecretV2) .whereIn(`${TableName.SecretV2}.folderId`, folderIds) .where((bd) => { @@ -700,22 +577,6 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { } ] }); - if (useCache) { - const cachedSecrets = data.map((el) => { - const encryptedValue = el.encryptedValue ? el.encryptedValue.toString("base64") : null; - const encryptedComment = el.encryptedComment ? el.encryptedComment.toString("base64") : null; - return { ...el, encryptedValue, encryptedComment }; - }); - const cache = JSON.stringify(cachedSecrets); - - if (Buffer.byteLength(cache, "utf8") < MAX_SECRET_CACHE_BYTES) { - await keyStore.setItemWithExpiry( - SecretDalCacheKeys.findByFolderIds(projectId, secretDalVersion, dto), - SECRET_DAL_TTL, - cache - ); - } - } return data; } catch (error) { diff --git a/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts b/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts index 4e7a5bca7..f42deb8ff 100644 --- a/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts +++ b/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts @@ -509,7 +509,7 @@ export const expandSecretReferencesFactory = ({ const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath); if (!folder) return { value: "", tags: [] }; - const secrets = await secretDAL.findByFolderId({ folderId: folder.id, projectId, useCache: true }); + const secrets = await secretDAL.findByFolderId({ folderId: folder.id }); const decryptedSecret = secrets.reduce>((prev, secret) => { // eslint-disable-next-line no-param-reassign diff --git a/backend/src/services/secret-v2-bridge/secret-v2-bridge-service.ts b/backend/src/services/secret-v2-bridge/secret-v2-bridge-service.ts index 596ebb5a1..ca815c6e1 100644 --- a/backend/src/services/secret-v2-bridge/secret-v2-bridge-service.ts +++ b/backend/src/services/secret-v2-bridge/secret-v2-bridge-service.ts @@ -25,6 +25,7 @@ import { TSecretApprovalPolicyServiceFactory } from "@app/ee/services/secret-app import { TSecretApprovalRequestDALFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-dal"; import { TSecretApprovalRequestSecretDALFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-secret-dal"; import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service"; +import { TKeyStoreFactory } from "@app/keystore/keystore"; import { DatabaseErrorCode } from "@app/lib/error-codes"; import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors"; import { diff, groupBy } from "@app/lib/fn"; @@ -43,7 +44,12 @@ import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal"; import { TSecretImportDALFactory } from "../secret-import/secret-import-dal"; import { fnSecretsV2FromImports } from "../secret-import/secret-import-fns"; import { TSecretTagDALFactory } from "../secret-tag/secret-tag-dal"; -import { TSecretV2BridgeDALFactory } from "./secret-v2-bridge-dal"; +import { + MAX_SECRET_CACHE_BYTES, + SECRET_DAL_TTL, + SecretServiceCacheKeys, + TSecretV2BridgeDALFactory +} from "./secret-v2-bridge-dal"; import { buildHierarchy, expandSecretReferencesFactory, @@ -105,6 +111,7 @@ type TSecretV2BridgeServiceFactoryDep = { >; snapshotService: Pick; resourceMetadataDAL: Pick; + keyStore: Pick; }; export type TSecretV2BridgeServiceFactory = ReturnType; @@ -127,7 +134,8 @@ export const secretV2BridgeServiceFactory = ({ secretApprovalRequestDAL, secretApprovalRequestSecretDAL, kmsService, - resourceMetadataDAL + resourceMetadataDAL, + keyStore }: TSecretV2BridgeServiceFactoryDep) => { const $validateSecretReferences = async ( projectId: string, @@ -800,12 +808,10 @@ export const secretV2BridgeServiceFactory = ({ const groupedFolderMappings = groupBy(folderMappings, (folderMapping) => folderMapping.folderId); const secrets = await secretDAL.findByFolderIds({ - projectId, folderIds: folderMappings.map((folderMapping) => folderMapping.folderId), userId, tx: undefined, - filters, - useCache: true + filters }); const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({ @@ -909,21 +915,22 @@ export const secretV2BridgeServiceFactory = ({ return decryptedSecrets; }; - const getSecrets = async ({ - actorId, - path, - environment, - projectId, - actor, - actorOrgId, - viewSecretValue, - actorAuthMethod, - includeImports, - recursive, - expandSecretReferences: shouldExpandSecretReferences, - throwOnMissingReadValuePermission = true, - ...params - }: TGetSecretsDTO) => { + const getSecrets = async (dto: TGetSecretsDTO) => { + const { + actorId, + path, + environment, + projectId, + actor, + actorOrgId, + viewSecretValue, + actorAuthMethod, + includeImports, + recursive, + expandSecretReferences: shouldExpandSecretReferences, + throwOnMissingReadValuePermission = true, + ...params + } = dto; const { permission } = await permissionService.getProjectPermission({ actor, actorId, @@ -934,6 +941,42 @@ export const secretV2BridgeServiceFactory = ({ }); throwIfMissingSecretReadValueOrDescribePermission(permission, ProjectPermissionSecretActions.DescribeSecret); + const cachedSecretDalVersion = await keyStore.getItem(SecretServiceCacheKeys.getSecretDalVersion(projectId)); + const secretDalVersion = Number(cachedSecretDalVersion || 0); + const cacheKey = SecretServiceCacheKeys.getSecretsOfServiceLayer(projectId, secretDalVersion, { + ...dto, + permissionRules: permission.rules + }); + + const { decryptor: secretManagerDecryptor, encryptor: secretManagerEncryptor } = + await kmsService.createCipherPairWithDataKey({ + type: KmsDataKey.SecretManager, + projectId + }); + + const encryptedCachedSecrets = await keyStore.getItem(cacheKey); + if (encryptedCachedSecrets) { + try { + await keyStore.setExpiry(cacheKey, SECRET_DAL_TTL); + const cachedSecrets = secretManagerDecryptor({ cipherTextBlob: Buffer.from(encryptedCachedSecrets, "base64") }); + const { secrets, imports = [] } = JSON.parse(cachedSecrets.toString("utf8")) as { + secrets: typeof decryptedSecrets; + imports: typeof importedSecrets; + }; + return { + secrets: secrets.map((el) => ({ + ...el, + createdAt: new Date(el.createdAt), + updatedAt: new Date(el.updatedAt) + })), + imports + }; + } catch (err) { + logger.error(err, "Secret service layer cache miss"); + await keyStore.deleteItem(cacheKey); + } + } + let paths: { folderId: string; path: string }[] = []; if (recursive) { @@ -958,17 +1001,10 @@ export const secretV2BridgeServiceFactory = ({ const groupedPaths = groupBy(paths, (p) => p.folderId); const secrets = await secretDAL.findByFolderIds({ - projectId, folderIds: paths.map((p) => p.folderId), userId: actorId, tx: undefined, - filters: params, - useCache: true - }); - - const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({ - type: KmsDataKey.SecretManager, - projectId + filters: params }); // scott: if any of this changes it also needs to be mirrored in secret rotation for getting dashboard secrets @@ -1086,15 +1122,19 @@ export const secretV2BridgeServiceFactory = ({ } if (!includeImports) { - return { - secrets: decryptedSecrets - }; + const payload = { secrets: decryptedSecrets, imports: [] }; + const encryptedUpdatedCachedSecrets = secretManagerEncryptor({ + plainText: Buffer.from(JSON.stringify(payload)) + }).cipherTextBlob; + if (encryptedUpdatedCachedSecrets.byteLength < MAX_SECRET_CACHE_BYTES) { + await keyStore.setItemWithExpiry(cacheKey, SECRET_DAL_TTL, encryptedUpdatedCachedSecrets.toString("base64")); + } + return payload; } const secretImports = await secretImportDAL.findByFolderIds(paths.map((p) => p.folderId)); const allowedImports = secretImports.filter(({ isReplication }) => !isReplication); const importedSecrets = await fnSecretsV2FromImports({ - projectId, viewSecretValue, secretImports: allowedImports, secretDAL, @@ -1129,10 +1169,14 @@ export const secretV2BridgeServiceFactory = ({ } }); - return { - secrets: decryptedSecrets, - imports: importedSecrets - }; + const payload = { secrets: decryptedSecrets, imports: importedSecrets }; + const encryptedUpdatedCachedSecrets = secretManagerEncryptor({ + plainText: Buffer.from(JSON.stringify(payload)) + }).cipherTextBlob; + if (encryptedUpdatedCachedSecrets.byteLength < MAX_SECRET_CACHE_BYTES) { + await keyStore.setItemWithExpiry(cacheKey, SECRET_DAL_TTL, encryptedUpdatedCachedSecrets.toString("base64")); + } + return payload; }; const getSecretById = async ({ actorId, actor, actorOrgId, actorAuthMethod, secretId }: TGetASecretByIdDTO) => { @@ -1312,7 +1356,6 @@ export const secretV2BridgeServiceFactory = ({ if (!secret && includeImports) { const secretImports = await secretImportDAL.find({ folderId, isReplication: false }); const importedSecrets = await fnSecretsV2FromImports({ - projectId, secretImports, viewSecretValue, secretDAL, @@ -2729,7 +2772,7 @@ export const secretV2BridgeServiceFactory = ({ generatePaths(folderMap).map(({ folderId, path }) => [folderId, path === "/" ? path : path.substring(1)]) ); - const secrets = await secretDAL.findByFolderIds({ folderIds: folders.map((f) => f.id), projectId, useCache: true }); + const secrets = await secretDAL.findByFolderIds({ folderIds: folders.map((f) => f.id) }); const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({ type: KmsDataKey.SecretManager, diff --git a/backend/src/services/secret/secret-queue.ts b/backend/src/services/secret/secret-queue.ts index 0d36250fb..5791c415d 100644 --- a/backend/src/services/secret/secret-queue.ts +++ b/backend/src/services/secret/secret-queue.ts @@ -367,7 +367,7 @@ export const secretQueueFactory = ({ canExpandValue: () => true }); // process secrets in current folder - const secrets = await secretV2BridgeDAL.findByFolderId({ folderId: dto.folderId, projectId: dto.projectId }); + const secrets = await secretV2BridgeDAL.findByFolderId({ folderId: dto.folderId }); await Promise.allSettled( secrets.map(async (secret) => { @@ -397,7 +397,6 @@ export const secretQueueFactory = ({ // if no imports then return secrets in the current folder if (!secretImports.length) return content; const importedSecrets = await fnSecretsV2FromImports({ - projectId: dto.projectId, decryptor: dto.decryptor, folderDAL, secretDAL: secretV2BridgeDAL, diff --git a/backend/src/services/smtp/smtp-service.ts b/backend/src/services/smtp/smtp-service.ts index 25f5f3949..550e1bb07 100644 --- a/backend/src/services/smtp/smtp-service.ts +++ b/backend/src/services/smtp/smtp-service.ts @@ -44,6 +44,7 @@ export enum SmtpTemplates { SecretRotationFailed = "secretRotationFailed.handlebars", ProjectAccessRequest = "projectAccess.handlebars", OrgAdminProjectDirectAccess = "orgAdminProjectGrantAccess.handlebars", + OrgAdminBreakglassAccess = "orgAdminBreakglassAccess.handlebars", ServiceTokenExpired = "serviceTokenExpired.handlebars" } diff --git a/backend/src/services/smtp/templates/orgAdminBreakglassAccess.handlebars b/backend/src/services/smtp/templates/orgAdminBreakglassAccess.handlebars new file mode 100644 index 000000000..cc97ff201 --- /dev/null +++ b/backend/src/services/smtp/templates/orgAdminBreakglassAccess.handlebars @@ -0,0 +1,20 @@ + + + + + + Organization admin has bypassed SSO + + + +

Infisical

+

The organization admin {{email}} has bypassed enforced SSO login.

+

Timestamp: {{timestamp}}

+

IP address: {{ip}}

+

User agent: {{userAgent}}

+

If you'd like to disable Admin SSO Bypass, please visit Organization Settings > Security.

+ + {{emailFooter}} + + + diff --git a/docs/api-reference/endpoints/project-groups/create.mdx b/docs/api-reference/endpoints/project-groups/create.mdx index 6b468085e..6dd7f1a4f 100644 --- a/docs/api-reference/endpoints/project-groups/create.mdx +++ b/docs/api-reference/endpoints/project-groups/create.mdx @@ -1,4 +1,4 @@ --- title: "Create Project Membership" -openapi: "POST /api/v2/workspace/{projectId}/groups/{groupId}" +openapi: "POST /api/v2/workspace/{projectId}/groups/{groupIdOrName}" --- diff --git a/docs/api-reference/endpoints/project-roles/create.mdx b/docs/api-reference/endpoints/project-roles/create.mdx index 7ebfff262..97570ec36 100644 --- a/docs/api-reference/endpoints/project-roles/create.mdx +++ b/docs/api-reference/endpoints/project-roles/create.mdx @@ -1,8 +1,10 @@ --- title: "Create" -openapi: "POST /api/v1/workspace/{projectSlug}/roles" +openapi: "POST /api/v2/workspace/{projectId}/roles" --- - You can read more about the permissions field in the [permissions documentation](/internals/permissions). - \ No newline at end of file + You can read more about the permissions field in the [permissions + documentation](/internals/permissions). + + diff --git a/docs/api-reference/endpoints/project-roles/delete.mdx b/docs/api-reference/endpoints/project-roles/delete.mdx index 6362c2154..41edfa7c3 100644 --- a/docs/api-reference/endpoints/project-roles/delete.mdx +++ b/docs/api-reference/endpoints/project-roles/delete.mdx @@ -1,4 +1,4 @@ --- title: "Delete" -openapi: "DELETE /api/v1/workspace/{projectSlug}/roles/{roleId}" +openapi: "DELETE /api/v2/workspace/{projectId}/roles/{roleId}" --- diff --git a/docs/api-reference/endpoints/project-roles/get-by-slug.mdx b/docs/api-reference/endpoints/project-roles/get-by-slug.mdx index 18817bca9..dfc5c582a 100644 --- a/docs/api-reference/endpoints/project-roles/get-by-slug.mdx +++ b/docs/api-reference/endpoints/project-roles/get-by-slug.mdx @@ -1,4 +1,4 @@ --- title: "Get By Slug" -openapi: "GET /api/v1/workspace/{projectSlug}/roles/slug/{slug}" +openapi: "GET /api/v2/workspace/{projectId}/roles/slug/{roleSlug}" --- diff --git a/docs/api-reference/endpoints/project-roles/list.mdx b/docs/api-reference/endpoints/project-roles/list.mdx index ca83d6e7d..8d8dc10c1 100644 --- a/docs/api-reference/endpoints/project-roles/list.mdx +++ b/docs/api-reference/endpoints/project-roles/list.mdx @@ -1,4 +1,4 @@ --- title: "List" -openapi: "GET /api/v1/workspace/{projectSlug}/roles" +openapi: "GET /api/v2/workspace/{projectId}/roles" --- diff --git a/docs/api-reference/endpoints/project-roles/update.mdx b/docs/api-reference/endpoints/project-roles/update.mdx index 5a3d9668e..662d5e617 100644 --- a/docs/api-reference/endpoints/project-roles/update.mdx +++ b/docs/api-reference/endpoints/project-roles/update.mdx @@ -1,4 +1,4 @@ --- title: "Update" -openapi: "PATCH /api/v1/workspace/{projectSlug}/roles/{roleId}" +openapi: "PATCH /api/v2/workspace/{projectId}/roles/{roleId}" --- diff --git a/docs/cli/overview.mdx b/docs/cli/overview.mdx index 89824e9f7..e0cbbe387 100644 --- a/docs/cli/overview.mdx +++ b/docs/cli/overview.mdx @@ -28,21 +28,32 @@ You can use it across various environments, whether it's local development, CI/C ``` - Use [Scoop](https://scoop.sh/) package manager - ```bash - scoop bucket add org https://github.com/Infisical/scoop-infisical.git - ``` + + Use [Scoop](https://scoop.sh/) package manager - ```bash - scoop install infisical - ``` + ```bash + scoop bucket add org https://github.com/Infisical/scoop-infisical.git + ``` - ### Updates + ```bash + scoop install infisical + ``` - ```bash - scoop update infisical - ``` + ### Updates + + ```bash + scoop update infisical + ``` + + + + Use [Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/) package manager + + ```bash + winget install infisical + ``` + diff --git a/docs/documentation/guides/organization-structure.mdx b/docs/documentation/guides/organization-structure.mdx index 6fd672164..3cba64678 100644 --- a/docs/documentation/guides/organization-structure.mdx +++ b/docs/documentation/guides/organization-structure.mdx @@ -6,40 +6,55 @@ description: "Learn how to structure your projects, secrets, and other resources Infisical is designed to provide comprehensive, centralized, and efficient management of secrets, certificates, and encryption keys within organizations. Below is an overview of Infisical's structured components, which developers and administrators can leverage for optimal project management and security posture. -### 1. Projects +### 0. Cluster/Instance + +- **Best Practice**: In most cases, a single Infisical instance or cluster is sufficient. Multiple clusters are typically only necessary for large, globally distributed organizations. +- **Use Cases**: + - **Cloud-hosted** deployments typically use a single cluster. While technically possible, using multiple clusters is not a common practice and is generally unnecessary. + - **Self-hosted** deployments can be configured with multiple clusters if needed. + + +### 1. Organization + +- **Definition**: An Infisical [organization](/documentation/platform/organization) is a set of projects that use the same billing. +- **Use Cases**: + - In **self-hosted** setups, you can create multiple organizations (e.g., one for each department or business unit). + - In **cloud-hosted deployments**, it's standard to use a single organization. + +### 2. Projects - **Definition and Role**: [Projects](/documentation/platform/project) are the highest-level construct within an [organization](/documentation/platform/organization) in Infisical. They serve as the primary container for all functionalities. - **Correspondence to Code Repositories**: Projects typically align with specific code repositories. - **Functional Capabilities**: Each project encompasses features for managing secrets, certificates, and encryption keys, serving as the central hub for these resources. -### 2. Environments +### 3. Environments - **Purpose**: Environments are designed for organizing and compartmentalizing secrets within projects. - **Customization Options**: Environments can be tailored to align with existing infrastructure setups of any project. Default options include **Development**, **Staging**, and **Production**. - **Structure**: Each environment inherently has a root level for storing secrets, but additional sub-organizations can be created through [folders](/documentation/platform/folder) for better secret management. -### 3. Folders +### 4. Folders - **Use Case**: Folders are available for more advanced organizational needs, allowing logical separation of secrets. - **Typical Structure**: Folders can correspond to specific logical units, such as microservices or different layers of an application, providing refined control over secrets. -### 4. Imports +### 5. Imports - **Purpose and Benefits**: To promote reusability and avoid redundancy, Infisical supports the use of imports. This allows secrets, folders, or entire environments to be referenced across multiple projects as needed. - **Best Practice**: Utilizing [secret imports](/documentation/platform/secret-reference#secret-imports) or [references](/documentation/platform/secret-reference#secret-referencing) ensures consistency and minimizes manual overhead. -### 5. Approval Workflows +### 6. Approval Workflows - **Importance**: Implementing approval workflows is recommended for organizations aiming to enhance efficiency and strengthen their security posture. - **Types of Workflows**: - **[Access Requests](/documentation/platform/pr-workflows)**: This workflow allows developers to request access to sensitive resources. Such access can be configured for temporary use, a practice known as "just-in-time" access. - **[Change Requests](/documentation/platform/access-controls/access-requests)**: Facilitates reviews and approvals when changes are proposed for sensitive environments or specific folders, ensuring proper oversight. -### 6. Access Controls +### 7. Access Controls Infisical’s access control framework is unified for both human users and machine identities, ensuring consistent management across the board. -### 6.1 Roles +### 7.1 Roles - **2 Role Types**: - **Organization-Level Roles**: Provide broad access across the organization (e.g., ability to manage billing, configure settings, etc.). @@ -49,17 +64,17 @@ Infisical’s access control framework is unified for both human users and machi Project access is defined not via an organization-level role, but rather through specific project memberships of both human and machine identities. Admin roles bypass this by default. -### 6.2 Additional Privileges +### 7.2 Additional Privileges [Additional privileges](/documentation/platform/access-controls/additional-privileges) can be assigned to users and machines on an ad-hoc basis for specific scenarios where roles alone are insufficient. If you find yourself using additional privileges too much, it is recommended to create custom roles. Additional privileges can be temporary or permanent. -### 6.3 Attribute-Based Access Control (ABAC) +### 7.3 Attribute-Based Access Control (ABAC) [Attribute-based Access Controls](/documentation/platform/access-controls/attribute-based-access-controls) allow restrictions based on tags or attributes linked to secrets. These can be integrated with SAML assertions and other security frameworks for dynamic access management. -### 6.4 User Groups +### 7.4 User Groups - **Application**: Organizations should use users groups in situations when they have a lot of developers with the same level of access (e.g., separated by team, department, seniority, etc.). - **Synchronization**: [User groups](/documentation/platform/groups) can be synced with an identity provider to maintain consistency and reduce manual management. diff --git a/docs/documentation/platform/dynamic-secrets/overview.mdx b/docs/documentation/platform/dynamic-secrets/overview.mdx index 1f17869ef..43e8867ab 100644 --- a/docs/documentation/platform/dynamic-secrets/overview.mdx +++ b/docs/documentation/platform/dynamic-secrets/overview.mdx @@ -41,3 +41,16 @@ Dynamic secrets are particularly useful in environments with stringent security 4. [Oracle](./oracle) 6. [Redis](./redis) 5. [AWS IAM](./aws-iam) + +**FAQ** + + + + This usually happens when the SQL statements defined for creating or revoking the secret are not compatible with your database provider. + + Different SQL engines have different expectations for quoting identifiers and values. For example, some use backticks (`` `username` ``), others use single quotes (`'username'`), and some expect double quotes (`"username"`). A statement that works on one provider might fail on another. + + **Recommendation:** + Make sure to adjust your SQL statements to follow the syntax required by your specific database provider. Always test them directly on your target database to ensure they execute without errors. + + diff --git a/docs/documentation/platform/kms-configuration/aws-kms.mdx b/docs/documentation/platform/kms-configuration/aws-kms.mdx index 598a3a32b..3fc5404ae 100644 --- a/docs/documentation/platform/kms-configuration/aws-kms.mdx +++ b/docs/documentation/platform/kms-configuration/aws-kms.mdx @@ -19,7 +19,7 @@ Before you begin, you'll first need to choose a method of authentication with AW ![IAM Role Creation](/images/integrations/aws/integration-aws-iam-assume-role.png) 2. Select **AWS Account** as the **Trusted Entity Type**. - 3. Choose **Another AWS Account** and enter **381492033652** (Infisical AWS Account ID). This restricts the role to be assumed only by Infisical. If you are self-hosting, provide the AWS account number where Infisical is hosted. + 3. Select **Another AWS Account** and provide the appropriate Infisical AWS Account ID: use **381492033652** for the **US region**, and **345594589636** for the **EU region**. This restricts the role to be assumed only by Infisical. If you are self-hosting, provide the AWS account number where Infisical is hosted. 4. Optionally, enable **Require external ID** and enter your Infisical **project ID** to further enhance security. diff --git a/docs/images/self-hosting/reference-architectures/google-cloud-run/cloud-run-container-image.png b/docs/images/self-hosting/reference-architectures/google-cloud-run/cloud-run-container-image.png new file mode 100644 index 000000000..b18fd7713 Binary files /dev/null and b/docs/images/self-hosting/reference-architectures/google-cloud-run/cloud-run-container-image.png differ diff --git a/docs/images/self-hosting/reference-architectures/google-cloud-run/container-env-vars.png b/docs/images/self-hosting/reference-architectures/google-cloud-run/container-env-vars.png new file mode 100644 index 000000000..ee5f9257b Binary files /dev/null and b/docs/images/self-hosting/reference-architectures/google-cloud-run/container-env-vars.png differ diff --git a/docs/images/self-hosting/reference-architectures/google-cloud-run/container-network-configuration.png b/docs/images/self-hosting/reference-architectures/google-cloud-run/container-network-configuration.png new file mode 100644 index 000000000..9a8ae13cb Binary files /dev/null and b/docs/images/self-hosting/reference-architectures/google-cloud-run/container-network-configuration.png differ diff --git a/docs/integrations/app-connections/aws.mdx b/docs/integrations/app-connections/aws.mdx index ab2f4638f..4944b0c34 100644 --- a/docs/integrations/app-connections/aws.mdx +++ b/docs/integrations/app-connections/aws.mdx @@ -55,7 +55,7 @@ Infisical supports two methods for connecting to AWS. ![IAM Role Creation](/images/integrations/aws/integration-aws-iam-assume-role.png) 2. Select **AWS Account** as the **Trusted Entity Type**. - 3. Choose **Another AWS Account** and enter **381492033652** (Infisical AWS Account ID). This restricts the role to be assumed only by Infisical. If self-hosting, provide your AWS account number instead. + 3. Select **Another AWS Account** and provide the appropriate Infisical AWS Account ID: use **381492033652** for the **US region**, and **345594589636** for the **EU region**. This restricts the role to be assumed only by Infisical. If self-hosting, provide your AWS account number instead. 4. (Recommended) Enable "Require external ID" and input your **Organization ID** to strengthen security and mitigate the [confused deputy problem](https://docs.aws.amazon.com/IAM/latest/UserGuide/confused-deputy.html). @@ -362,4 +362,5 @@ Infisical supports two methods for connecting to AWS. + diff --git a/docs/mint.json b/docs/mint.json index 6c2f51a96..b5523747f 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -314,6 +314,13 @@ "self-hosting/deployment-options/kubernetes-helm" ] }, + { + "group": "Linux Package", + "pages": [ + "self-hosting/deployment-options/native/linux-package/installation", + "self-hosting/deployment-options/native/linux-package/commands-configuration" + ] + }, "self-hosting/guides/upgrading-infisical", "self-hosting/configuration/envars", "self-hosting/configuration/requirements", @@ -330,7 +337,8 @@ "pages": [ "self-hosting/reference-architectures/aws-ecs", "self-hosting/reference-architectures/linux-deployment-ha", - "self-hosting/reference-architectures/on-prem-k8s-ha" + "self-hosting/reference-architectures/on-prem-k8s-ha", + "self-hosting/reference-architectures/google-cloud-run" ] }, "self-hosting/ee", diff --git a/docs/self-hosting/deployment-options/native/linux-package/commands-configuration.mdx b/docs/self-hosting/deployment-options/native/linux-package/commands-configuration.mdx new file mode 100644 index 000000000..61be021b6 --- /dev/null +++ b/docs/self-hosting/deployment-options/native/linux-package/commands-configuration.mdx @@ -0,0 +1,38 @@ +--- +title: "Configurations" +description: "Learn how to configure and manage the Infisical Linux package" +--- + +## Configuration Overview + +All configuration for the Infisical Linux package is managed through a single file called `infisical.rb`, located in the `/etc/infisical` directory. +This file defines all necessary settings, including encryption keys, database connections, and environment-specific settings. + + After making any changes to the `infisical.rb` file, always run `infisical-ctl reconfigure` to apply them. + +### Example Configuration + +```ruby infisical.rb +# Important: Replace these values with secure keys in production +infisical_core['ENCRYPTION_KEY'] = '6c1fe4e407b8911c104518103505b218' +infisical_core['AUTH_SECRET'] = '5lrMXKKWCVocS/uerPsl7V+TX/aaUaI7iDkgl3tSmLE=' + +# Database connection strings +infisical_core['DB_CONNECTION_URI'] = 'postgres://:@:5432/' +infisical_core['REDIS_URL'] = 'redis://:6379' +``` + +For a full list of supported configuration variables, refer to the [configuration variables documentation](/self-hosting/configuration/envars). + +## All `infisical-ctl` Commands + +The Infisical Linux package includes the `infisical-ctl` command-line tool, which allows you to manage your deployment. +The available commands are listed below. + +| Command | Description | +|-----------------------------|-----------------------------------------------------------------------------| +| `infisical-ctl reconfigure` | Applies changes from `infisical.rb` and restarts the Infisical services. | +| `infisical-ctl start` | Starts the Infisical services. | +| `infisical-ctl stop` | Stops all running Infisical services. | +| `infisical-ctl status` | Displays the current status of the Infisical services. | +| `infisical-ctl tail` | Streams real-time logs from the Infisical application. | \ No newline at end of file diff --git a/docs/self-hosting/deployment-options/native/linux-package/installation.mdx b/docs/self-hosting/deployment-options/native/linux-package/installation.mdx new file mode 100644 index 000000000..30ef83242 --- /dev/null +++ b/docs/self-hosting/deployment-options/native/linux-package/installation.mdx @@ -0,0 +1,122 @@ +--- +title: "Installation" +description: "Learn how to deploy Infisical using the Linux package" +--- + +Infisical can be deployed on Linux virtual machines without the need for containers using our standalone Linux packages. +These packages are available in both .deb (for Debian-based systems) and .rpm (for RHEL-based systems) formats. +The installation includes the Infisical service, along with a CLI tool (infisical-ctl) to help you manage configurations, startup, and application logging. +This approach is ideal for environments where containerization isn't desired, while still providing a lightweight deployment option. + +## Prerequisites + +This installation method only provides the Infisical application. You are responsible for configuring both PostgreSQL and Redis, either by using managed services (e.g., AWS RDS, Azure Database, GCP Cloud SQL/Memorystore) or by deploying them manually in your on-prem environment. +Please ensure you have the following before beginning installation of Infisical: + +- A Linux server running a Debian/Ubuntu or RHEL-based distribution +- A running PostgreSQL database instance (version 14 and up) +- A running Redis database instance (versions 6.x or 7.x) + +## Installation Steps + + + + + Select your Linux distribution to get started. Only AMD64-based systems are supported at this time, ARM support is coming soon. + + + + + Add the Infisical repository: + ```bash + curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-core/setup.deb.sh' | sudo -E bash + ``` + + Install Infisical: + ```bash + sudo apt-get update && sudo apt-get install -y infisical-core + ``` + + > **Note**: For production use, we recommend locking to a specific version to ensure consistency. [View available versions](https://cloudsmith.io/~infisical/repos/infisical-core/packages/). + + + + Add the Infisical repository: + ```bash + curl -1sLf 'https://dl.cloudsmith.io/public/infisical/infisical-core/setup.rpm.sh' | sudo -E bash + ``` + + Install Infisical: + ```bash + sudo yum install infisical-core + ``` + + > **Note**: For production use, we recommend locking to a specific version to ensure consistency. [View available versions](https://cloudsmith.io/~infisical/repos/infisical-core/packages/). + + + + + Verify the installation: + ```bash + infisical-ctl help + ``` + + + + Create an `infisical.rb` file at `/etc/infisical`. This file contains your database connection strings and other runtime settings. + + ```ruby + # Important: Replace with secure values in production + infisical_core['ENCRYPTION_KEY'] = '6c1fe4e407b8911c104518103505b218' + infisical_core['AUTH_SECRET'] = '5lrMXKKWCVocS/uerPsl7V+TX/aaUaI7iDkgl3tSmLE=' + + # Example database connection strings + infisical_core['DB_CONNECTION_URI'] = 'postgres://:@:/' + infisical_core['REDIS_URL'] = 'redis://:' + ``` + + See the full list of options in our [configuration documentation](/self-hosting/configuration/envars). + + + + 1. Start the Infisical service: + ```bash + infisical-ctl reconfigure + ``` + The server runs on port `8080` by default (customizable in `infisical.rb`). + + 2. Check the service status: + ```bash + infisical-ctl status + ``` + + View the service logs in real-time: + ```bash + infisical-ctl tail + ``` + + + + +## Platform Support + +### Microsoft Windows +Infisical is built for Linux-based systems. It is not supported on Microsoft Windows, and we do not plan to support it in the near future. For Windows users, consider running Infisical in a virtual machine or WSL2 environment. + +### Unsupported Linux Distributions and Unix-like Systems +Infisical is not tested or officially supported on the following: + +- Arch Linux +- Fedora +- FreeBSD +- Gentoo +- macOS + +We recommend sticking to officially supported distributions for the best experience. + +## Linux vs Containerized Deployments + +Infisical is a stateless application, which means it can be easily scaled and redeployed without maintaining internal state between instances. + +If your use case requires rolling updates, self-healing, or auto-scaling, we recommend deploying Infisical in a containerized environment such as Kubernetes/OpenShift, or using managed container orchestration services like AWS ECS or Google Cloud Run. +These platforms offer built-in capabilities for high availability and help simplify operational overhead for your deployment. \ No newline at end of file diff --git a/docs/self-hosting/overview.mdx b/docs/self-hosting/overview.mdx index a7ea50e39..acb692711 100644 --- a/docs/self-hosting/overview.mdx +++ b/docs/self-hosting/overview.mdx @@ -33,21 +33,10 @@ Choose from a number of deployment options listed below to get started. Use our Helm chart to Install Infisical on your Kubernetes cluster. -{/* - - Install Infisical on your Debian-based system without containers using our standalone binary. - - - Install Infisical on your Debian-based instances without containers using our standalone binary with high availability out of the box. - - */} + Install Infisical on your system without containers using our Linux package. + diff --git a/docs/self-hosting/reference-architectures/google-cloud-run.mdx b/docs/self-hosting/reference-architectures/google-cloud-run.mdx new file mode 100644 index 000000000..36fa1de24 --- /dev/null +++ b/docs/self-hosting/reference-architectures/google-cloud-run.mdx @@ -0,0 +1,114 @@ +--- +title: "Google Cloud Run" +description: "Reference architecture for self-hosting Infisical on Google Cloud Run." +--- + +## Overview +This guide outlines a reference architecture for deploying Infisical in a self-hosted configuration using Google Cloud Run. +It is intended to provide a scalable, secure, and production-ready baseline for organizations choosing Google Cloud Platform (GCP) as their infrastructure provider. + +## Core Components + +- **Cloud Run:** Infisical service is containerized and deployed as fully managed Cloud Run services. + +- **Cloud SQL:** Infisical uses Postgres as its persistence layer. As such, Cloud SQL for PostgreSQL is used. + +- **MemoryStore for Redis:** To schedule jobs, process audit logs and cache performance, Infisical requires Redis. + +## Securing Infisical's root credential + +- **Secrets Manager:** To secure Infisical’s root credentials (database connection string, encryption key, etc.), +we highly recommend that you use Google Secrets Manager and only allow the tasks running Infisical to access them. + +## High Availability and Scalability + +This architecture leverages Google Cloud's managed services to achieve high availability and scalability out of the box: + +**Cloud Run:** + +- Automatically scales the number of container instances up or down based on incoming request volume. +- Supports rapid scaling during traffic spikes, ensuring low latency. +- Configurable minimum and maximum instances to handle baseline and peak loads. + +**Cloud SQL:** + +- Provides high availability configurations (regional instances with automatic failover) to ensure database uptime. +- Automated backups, point-in-time recovery, and maintenance. + +**MemoryStore:** + +- Offers highly available Redis configurations with replication. +- Fully managed with automatic scaling and patching. + +**Cloud Load Balancer:** + +- Distributes user traffic across available Cloud Run instances. +- Provides SSL termination, global load balancing, and health checks. + + + **Note:** To further improve performance and availability, consider enabling multi-region deployment strategies, + regional VPC Connectors, and database replicas for read-heavy workloads. + + +## Configuration + + + + **Cloud SQL (PostgreSQL):** + - Create a Cloud SQL instance. + - Under `Zonal availability`, select the `Multiple zones` option to ensure High Availability. + - Configure private IP access. + + **MemoryStore (Redis):** + - Deploy a Redis instance. + - Configure VPC access. + + + + Visit [Docker Hub](https://hub.docker.com/r/infisical/infisical/tags) and select a version of Infisical image you would like to deploy. + Then, within Cloud Run, paste the URL of the specific Infisical Docker image you would like to use within the `Container image URL` field. + + ![Cloud Run container image settings UI](/images/self-hosting/reference-architectures/google-cloud-run/cloud-run-container-image.png) + + Remember to replace `` with the docker image tag of your choice. + + + For a minimal installation of Infisical, you must configure the following environment variables: + + ```bash + ENCRYPTION_KEY= + AUTH_SECRET= + DB_CONNECTION_URI="" + SITE_URL="" + REDIS_URL="" + ``` + [View all available configurations](/self-hosting/configuration/envars). + + You will want to setup Postgres and Redis within Google Cloud Platform to connect to Infisical. + + Once you have added the required environment variables to the `Environment Variables` section within Cloud Run, + create the container to get Infisical up and running. + + ![Cloud Run container environment variables settings UI](/images/self-hosting/reference-architectures/google-cloud-run/container-env-vars.png) + + + The above environment variable values are only to be used as an example and should not be used in production + + + + + + Enable `Connect to a VPC for outbound traffic`: This enables the service to talk to private resources (e.g., a Cloud SQL database, Redis instance on a private IP) inside your Google Cloud VPC network. + + Select `Send traffic directly to a VPC`: It gives lower latency and better performance, but uses more IPs from the subnet. + + + Your Cloud Run revision must be in the same VPC network + + + ![Cloud Run container network settings UI](/images/self-hosting/reference-architectures/google-cloud-run/container-network-configuration.png) + + Once the container is running, verify the installation by opening your web browser and navigating to the Site URL. + + + \ No newline at end of file diff --git a/frontend/public/lotties/notification-bell.json b/frontend/public/lotties/notification-bell.json new file mode 100644 index 000000000..56d4c9950 --- /dev/null +++ b/frontend/public/lotties/notification-bell.json @@ -0,0 +1 @@ +{"v":"5.12.1","fr":60,"ip":0,"op":90,"w":500,"h":500,"nm":"system-regular-46-notification-bell","ddd":0,"assets":[{"id":"comp_1","nm":"hover-bell","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".primary.design","cl":"primary design","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.231],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.313],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7.041,"s":[5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":19,"s":[-53]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":29,"s":[-20]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":39,"s":[-62]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":49,"s":[-20]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":58,"s":[-62]},{"i":{"x":[0.283],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":69.713,"s":[14]},{"t":79,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.231,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[249.998,67.334,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.313,"y":1},"o":{"x":0.333,"y":0},"t":7.041,"s":[269.998,67.334,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":19,"s":[111.998,67.334,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.313,"y":1},"o":{"x":0.333,"y":0},"t":29,"s":[121.998,67.334,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":39,"s":[111.998,67.334,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":49,"s":[121.998,67.334,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":58,"s":[111.998,67.334,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.283,"y":1},"o":{"x":0.333,"y":0},"t":69.713,"s":[261.998,67.334,0],"to":[0,0,0],"ti":[0,0,0]},{"t":79,"s":[249.998,67.334,0]}],"ix":2,"l":2},"a":{"a":0,"k":[249.998,67.334,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,6.468],[0,0],[60.406,0],[0,0],[0,-60.406],[0,0],[2.893,-5.786],[0,0],[0,0]],"o":[[-2.893,-5.786],[0,0],[0,-60.406],[0,0],[-60.406,0],[0,0],[0,6.468],[0,0],[0,0],[0,0]],"v":[[113.773,55.671],[109.375,37.038],[109.375,-20.834],[0.001,-130.21],[-0.001,-130.21],[-109.375,-20.834],[-109.375,37.038],[-113.773,55.671],[-151.042,130.21],[151.042,130.21]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3,"x":"var $bm_rt;\n$bm_rt = comp('system-regular-46-notification-bell').layer('control').effect('primary')('Color');"},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":31.3,"ix":5},"lc":2,"lj":2,"bm":0,"nm":".primary","mn":"ADBE Vector Graphic - Stroke","hd":false,"cl":"primary"},{"ty":"tr","p":{"a":0,"k":[249.998,229.166],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,-20.832],[0,20.832]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3,"x":"var $bm_rt;\n$bm_rt = comp('system-regular-46-notification-bell').layer('control').effect('primary')('Color');"},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":31.3,"ix":5},"lc":2,"lj":2,"bm":0,"nm":".primary","mn":"ADBE Vector Graphic - Stroke","hd":false,"cl":"primary"},{"ty":"tr","p":{"a":0,"k":[249.998,78.125],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":90,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".primary.design","cl":"primary design","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[-26]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":32,"s":[29]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":42,"s":[-28]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":52,"s":[29]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":61,"s":[-28]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":73,"s":[29]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":83,"s":[-6]},{"t":90,"s":[0]}],"ix":10},"p":{"a":0,"k":[249.998,182.041,0],"ix":2,"l":2},"a":{"a":0,"k":[0,-219,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-25.889,0],[0,25.889],[0,0]],"o":[[0,0],[0,25.889],[25.888,0],[0,0],[0,0]],"v":[[-46.751,-119.666],[-46.875,-5.21],[0.001,41.666],[46.875,-5.21],[46.998,-119.666]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3,"x":"var $bm_rt;\n$bm_rt = comp('system-regular-46-notification-bell').layer('control').effect('primary')('Color');"},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":31.3,"ix":5},"lc":2,"lj":2,"bm":0,"nm":".primary","mn":"ADBE Vector Graphic - Stroke","hd":false,"cl":"primary"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":1,"s":[23]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[33]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[22.538]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[21]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":28,"s":[22.538]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":32,"s":[33]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[22.538]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":42,"s":[21]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[22.538]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":52,"s":[33]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":57,"s":[22.538]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":61,"s":[21]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":67,"s":[22.538]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":73,"s":[33]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":78,"s":[22.538]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":83,"s":[21]},{"t":90,"s":[22.538]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[79]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[77.077]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[68]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":28,"s":[77.077]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":32,"s":[79]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":37,"s":[77.077]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":42,"s":[68]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":47,"s":[77.077]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":52,"s":[79]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":57,"s":[77.077]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":61,"s":[68]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":67,"s":[77.077]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":73,"s":[79]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":78,"s":[77.077]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":83,"s":[75]},{"t":90,"s":[77.077]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":1,"op":90,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".primary.design","cl":"primary design","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250.038,250.002,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[2083,2083,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0.43],[0,0],[-2.48,0],[0,-2.48],[0,0],[-0.19,-0.38],[0,0]],"o":[[0,0],[0.19,-0.38],[0,0],[0,-2.48],[2.48,0],[0,0],[0,0.42],[0,0],[0,0]],"v":[[-6.042,4.5],[-4.792,2.01],[-4.502,0.78],[-4.502,-2],[-0.002,-6.5],[4.498,-2],[4.498,0.78],[4.788,2.01],[6.038,4.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0.19],[0,0],[2.96,0.37],[0,0],[0.41,0],[0,-0.41],[0,0],[0,-3.05],[0,0],[0.08,-0.17],[0,0],[-0.13,-0.22],[-0.26,0],[0,0],[-0.14,0.23],[0.12,0.23]],"o":[[-0.08,-0.18],[0,0],[0,-3.05],[0,0],[0,-0.41],[-0.41,0],[0,0],[-2.96,0.37],[0,0],[0,0.19],[0,0],[-0.12,0.23],[0.14,0.22],[0,0],[0.26,0],[0.14,-0.22],[0,0]],"v":[[6.128,1.34],[5.998,0.78],[5.998,-2],[0.748,-7.95],[0.748,-9.25],[-0.002,-10],[-0.752,-9.25],[-0.752,-7.95],[-6.002,-2],[-6.002,0.78],[-6.132,1.34],[-7.922,4.92],[-7.892,5.65],[-7.252,6],[7.248,6],[7.888,5.64],[7.918,4.91]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4,"x":"var $bm_rt;\n$bm_rt = comp('system-regular-46-notification-bell').layer('control').effect('primary')('Color');"},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":".primary","mn":"ADBE Vector Graphic - Fill","hd":false,"cl":"primary"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".primary.design","cl":"primary design","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250.038,250.002,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[2083,2083,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.83,0],[0,0.83],[0,0],[0,0]],"o":[[0,0.83],[-0.83,0],[0,0],[0,0],[0,0]],"v":[[1.498,7],[-0.002,8.5],[-1.502,7],[-1.501,5.544],[1.499,5.544]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-1.65,0],[0,1.65],[0,0]],"o":[[0,0],[0,1.65],[1.65,0],[0,0],[0,0]],"v":[[-3.001,5.088],[-3.002,7],[-0.002,10],[2.998,7],[2.999,5.088]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4,"x":"var $bm_rt;\n$bm_rt = comp('system-regular-46-notification-bell').layer('control').effect('primary')('Color');"},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":".primary","mn":"ADBE Vector Graphic - Fill","hd":false,"cl":"primary"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".primary.design","cl":"primary design","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250.038,250.002,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[2083,2083,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0.43],[0,0],[-2.48,0],[0,-2.48],[0,0],[-0.19,-0.38],[0,0]],"o":[[0,0],[0.19,-0.38],[0,0],[0,-2.48],[2.48,0],[0,0],[0,0.42],[0,0],[0,0]],"v":[[-6.042,4.5],[-4.792,2.01],[-4.502,0.78],[-4.502,-2],[-0.002,-6.5],[4.498,-2],[4.498,0.78],[4.788,2.01],[6.038,4.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0.19],[0,0],[2.96,0.37],[0,0],[0.41,0],[0,-0.41],[0,0],[0,-3.05],[0,0],[0.08,-0.17],[0,0],[-0.13,-0.22],[-0.26,0],[0,0],[-0.14,0.23],[0.12,0.23]],"o":[[-0.08,-0.18],[0,0],[0,-3.05],[0,0],[0,-0.41],[-0.41,0],[0,0],[-2.96,0.37],[0,0],[0,0.19],[0,0],[-0.12,0.23],[0.14,0.22],[0,0],[0.26,0],[0.14,-0.22],[0,0]],"v":[[6.128,1.34],[5.998,0.78],[5.998,-2],[0.748,-7.95],[0.748,-9.25],[-0.002,-10],[-0.752,-9.25],[-0.752,-7.95],[-6.002,-2],[-6.002,0.78],[-6.132,1.34],[-7.922,4.92],[-7.892,5.65],[-7.252,6],[7.248,6],[7.888,5.64],[7.918,4.91]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4,"x":"var $bm_rt;\n$bm_rt = comp('system-regular-46-notification-bell').layer('control').effect('primary')('Color');"},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":".primary","mn":"ADBE Vector Graphic - Fill","hd":false,"cl":"primary"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":90,"op":300,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".primary.design","cl":"primary design","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250.038,250.002,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[2083,2083,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.83,0],[0,0.83],[0,0],[0,0]],"o":[[0,0.83],[-0.83,0],[0,0],[0,0],[0,0]],"v":[[1.498,7],[-0.002,8.5],[-1.502,7],[-1.501,5.544],[1.499,5.544]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-1.65,0],[0,1.65],[0,0]],"o":[[0,0],[0,1.65],[1.65,0],[0,0],[0,0]],"v":[[-3.001,5.088],[-3.002,7],[-0.002,10],[2.998,7],[2.999,5.088]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4,"x":"var $bm_rt;\n$bm_rt = comp('system-regular-46-notification-bell').layer('control').effect('primary')('Color');"},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":".primary","mn":"ADBE Vector Graphic - Fill","hd":false,"cl":"primary"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":90,"op":300,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"control","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ef":[{"ty":5,"nm":"primary","np":3,"mn":"ADBE Color Control","ix":1,"en":1,"ef":[{"ty":2,"nm":"Color","mn":"ADBE Color Control-0001","ix":1,"v":{"a":0,"k":[1,1,1],"ix":1}}]}],"ip":0,"op":291,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"hover-bell","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[250,250,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":500,"h":500,"ip":0,"op":100,"st":0,"bm":0}],"markers":[{"tm":0,"cm":"default:hover-bell","dr":90}],"props":{}} \ No newline at end of file diff --git a/frontend/src/const/routes.ts b/frontend/src/const/routes.ts index 2be3f3dbc..cd3c6675f 100644 --- a/frontend/src/const/routes.ts +++ b/frontend/src/const/routes.ts @@ -281,6 +281,14 @@ export const ROUTE_PATHS = Object.freeze({ "/cert-manager/$projectId/overview", "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/overview" ), + CertificateAuthoritiesPage: setRoute( + "/cert-manager/$projectId/certificate-authorities", + "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-authorities" + ), + AlertingPage: setRoute( + "/cert-manager/$projectId/alerting", + "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/alerting" + ), PkiCollectionDetailsByIDPage: setRoute( "/cert-manager/$projectId/pki-collections/$collectionId", "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/pki-collections/$collectionId" diff --git a/frontend/src/hooks/api/auditLogs/constants.tsx b/frontend/src/hooks/api/auditLogs/constants.tsx index 159e840ec..229f822da 100644 --- a/frontend/src/hooks/api/auditLogs/constants.tsx +++ b/frontend/src/hooks/api/auditLogs/constants.tsx @@ -84,6 +84,7 @@ export const eventToNameMap: { [K in EventType]: string } = { [EventType.ADD_PKI_COLLECTION_ITEM]: "Add PKI collection item", [EventType.DELETE_PKI_COLLECTION_ITEM]: "Delete PKI collection item", [EventType.ORG_ADMIN_ACCESS_PROJECT]: "Org admin accessed project", + [EventType.ORG_ADMIN_BYPASS_SSO]: "Org admin bypassed SSO enforcement", [EventType.CREATE_CERTIFICATE_TEMPLATE]: "Create certificate template", [EventType.UPDATE_CERTIFICATE_TEMPLATE]: "Update certificate template", [EventType.DELETE_CERTIFICATE_TEMPLATE]: "Delete certificate template", diff --git a/frontend/src/hooks/api/auditLogs/enums.tsx b/frontend/src/hooks/api/auditLogs/enums.tsx index 15adb0272..d465fb820 100644 --- a/frontend/src/hooks/api/auditLogs/enums.tsx +++ b/frontend/src/hooks/api/auditLogs/enums.tsx @@ -90,6 +90,7 @@ export enum EventType { ADD_PKI_COLLECTION_ITEM = "add-pki-collection-item", DELETE_PKI_COLLECTION_ITEM = "delete-pki-collection-item", ORG_ADMIN_ACCESS_PROJECT = "org-admin-accessed-project", + ORG_ADMIN_BYPASS_SSO = "org-admin-bypassed-sso", CREATE_CERTIFICATE_TEMPLATE = "create-certificate-template", UPDATE_CERTIFICATE_TEMPLATE = "update-certificate-template", DELETE_CERTIFICATE_TEMPLATE = "delete-certificate-template", diff --git a/frontend/src/hooks/api/auditLogs/types.tsx b/frontend/src/hooks/api/auditLogs/types.tsx index a18974f2e..2524f84f4 100644 --- a/frontend/src/hooks/api/auditLogs/types.tsx +++ b/frontend/src/hooks/api/auditLogs/types.tsx @@ -718,6 +718,11 @@ interface OrgAdminAccessProjectEvent { }; // no metadata yet } +interface OrgAdminBypassSSOEvent { + type: EventType.ORG_ADMIN_BYPASS_SSO; + metadata: Record; // no metadata yet +} + interface CreateCertificateTemplate { type: EventType.CREATE_CERTIFICATE_TEMPLATE; metadata: { @@ -885,6 +890,7 @@ export type Event = | AddPkiCollectionItem | DeletePkiCollectionItem | OrgAdminAccessProjectEvent + | OrgAdminBypassSSOEvent | CreateCertificateTemplate | UpdateCertificateTemplate | GetCertificateTemplate diff --git a/frontend/src/layouts/ProjectLayout/ProjectLayout.tsx b/frontend/src/layouts/ProjectLayout/ProjectLayout.tsx index e1fd2e4bf..7aed0a6e8 100644 --- a/frontend/src/layouts/ProjectLayout/ProjectLayout.tsx +++ b/frontend/src/layouts/ProjectLayout/ProjectLayout.tsx @@ -92,18 +92,46 @@ export const ProjectLayout = () => { )} {isCertManager && ( - - {({ isActive }) => ( - - Overview - - )} - + <> + + {({ isActive }) => ( + + Certificates + + )} + + + {({ isActive }) => ( + + Certificate Authorities + + )} + + + {({ isActive }) => ( + + Alerting + + )} + + )} {isCmek && ( { + const { t } = useTranslation(); + return ( +
+ + {t("common.head-title", { title: "Alerting" })} + +
+ + + + +
+
+ ); +}; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/PkiAlertModal.tsx b/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertModal.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/PkiAlertModal.tsx rename to frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertModal.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/PkiAlertRow.tsx b/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertRow.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/PkiAlertRow.tsx rename to frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertRow.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/PkiAlertsSection.tsx b/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertsSection.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/PkiAlertsSection.tsx rename to frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertsSection.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/PkiAlertsTable.tsx b/frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertsTable.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/PkiAlertsTable.tsx rename to frontend/src/pages/cert-manager/AlertingPage/components/PkiAlertsTable.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/PkiCollectionModal.tsx b/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionModal.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/PkiCollectionModal.tsx rename to frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionModal.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/PkiCollectionSection.tsx b/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionSection.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/PkiCollectionSection.tsx rename to frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionSection.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/PkiCollectionTable.tsx b/frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionTable.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/PkiCollectionTable.tsx rename to frontend/src/pages/cert-manager/AlertingPage/components/PkiCollectionTable.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/index.tsx b/frontend/src/pages/cert-manager/AlertingPage/components/index.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/components/index.tsx rename to frontend/src/pages/cert-manager/AlertingPage/components/index.tsx diff --git a/frontend/src/pages/cert-manager/AlertingPage/route.tsx b/frontend/src/pages/cert-manager/AlertingPage/route.tsx new file mode 100644 index 000000000..d14e64d94 --- /dev/null +++ b/frontend/src/pages/cert-manager/AlertingPage/route.tsx @@ -0,0 +1,19 @@ +import { createFileRoute } from "@tanstack/react-router"; + +import { AlertingPage } from "./AlertingPage"; + +export const Route = createFileRoute( + "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/alerting" +)({ + component: AlertingPage, + beforeLoad: ({ context }) => { + return { + breadcrumbs: [ + ...context.breadcrumbs, + { + label: "Alerting" + } + ] + }; + } +}); diff --git a/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/CertAuthDetailsByIDPage.tsx b/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/CertAuthDetailsByIDPage.tsx index 75d0ca139..9bb6c9096 100644 --- a/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/CertAuthDetailsByIDPage.tsx +++ b/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/CertAuthDetailsByIDPage.tsx @@ -20,9 +20,9 @@ import { useDeleteCa, useGetCaById } from "@app/hooks/api"; import { ProjectType } from "@app/hooks/api/workspace/types"; import { usePopUp } from "@app/hooks/usePopUp"; -import { CaInstallCertModal } from "../CertificatesPage/components/CaTab/components/CaInstallCertModal"; -import { CaModal } from "../CertificatesPage/components/CaTab/components/CaModal"; -import { CertificateTemplatesSection } from "../CertificatesPage/components/CertificatesTab/components/CertificateTemplatesSection"; +import { CaInstallCertModal } from "../CertificateAuthoritiesPage/components/CaInstallCertModal"; +import { CaModal } from "../CertificateAuthoritiesPage/components/CaModal"; +import { CertificateTemplatesSection } from "../CertificatesPage/components/CertificateTemplatesSection"; import { CaCertificatesSection, CaCrlsSection, diff --git a/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/route.tsx b/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/route.tsx index 00244eb98..aa7540a7f 100644 --- a/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/route.tsx +++ b/frontend/src/pages/cert-manager/CertAuthDetailsByIDPage/route.tsx @@ -13,7 +13,7 @@ export const Route = createFileRoute( { label: "Certificate Authorities", link: linkOptions({ - to: "/cert-manager/$projectId/overview", + to: "/cert-manager/$projectId/certificate-authorities", params: { projectId: params.projectId } diff --git a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/CertificateAuthoritiesPage.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/CertificateAuthoritiesPage.tsx new file mode 100644 index 000000000..f74ececaf --- /dev/null +++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/CertificateAuthoritiesPage.tsx @@ -0,0 +1,29 @@ +import { Helmet } from "react-helmet"; +import { useTranslation } from "react-i18next"; + +import { ProjectPermissionCan } from "@app/components/permissions"; +import { PageHeader } from "@app/components/v2"; +import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context"; + +import { CaSection } from "./components"; + +export const CertificateAuthoritiesPage = () => { + const { t } = useTranslation(); + return ( +
+ + {t("common.head-title", { title: "Certificate Authorities" })} + +
+ + + + +
+
+ ); +}; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaCertModal.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaCertModal.tsx similarity index 91% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaCertModal.tsx rename to frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaCertModal.tsx index 97970d94f..113a88c48 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaCertModal.tsx +++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaCertModal.tsx @@ -2,7 +2,7 @@ import { Modal, ModalContent } from "@app/components/v2"; import { useGetCaCert } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; -import { CertificateContent } from "../../CertificatesTab/components/CertificateContent"; +import { CertificateContent } from "../../CertificatesPage/components/CertificateContent"; type Props = { popUp: UsePopUpState<["caCert"]>; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaInstallCertModal/CaInstallCertModal.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/CaInstallCertModal.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaInstallCertModal/CaInstallCertModal.tsx rename to frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/CaInstallCertModal.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaInstallCertModal/ExternalCaInstallForm.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/ExternalCaInstallForm.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaInstallCertModal/ExternalCaInstallForm.tsx rename to frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/ExternalCaInstallForm.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaInstallCertModal/InternalCaInstallForm.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/InternalCaInstallForm.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaInstallCertModal/InternalCaInstallForm.tsx rename to frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/InternalCaInstallForm.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaInstallCertModal/index.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/index.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaInstallCertModal/index.tsx rename to frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaInstallCertModal/index.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaModal.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaModal.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaModal.tsx rename to frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaModal.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaSection.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaSection.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaSection.tsx rename to frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaSection.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaTable.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaTable.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/CaTable.tsx rename to frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/CaTable.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/index.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/index.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/components/index.tsx rename to frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/index.tsx diff --git a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/route.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/route.tsx new file mode 100644 index 000000000..e11496710 --- /dev/null +++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/route.tsx @@ -0,0 +1,19 @@ +import { createFileRoute } from "@tanstack/react-router"; + +import { CertificateAuthoritiesPage } from "./CertificateAuthoritiesPage"; + +export const Route = createFileRoute( + "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-authorities" +)({ + component: CertificateAuthoritiesPage, + beforeLoad: ({ context }) => { + return { + breadcrumbs: [ + ...context.breadcrumbs, + { + label: "Certificate Authorities" + } + ] + }; + } +}); diff --git a/frontend/src/pages/cert-manager/CertificatesPage/CertificatesPage.tsx b/frontend/src/pages/cert-manager/CertificatesPage/CertificatesPage.tsx index 0d212e797..c985f313f 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/CertificatesPage.tsx +++ b/frontend/src/pages/cert-manager/CertificatesPage/CertificatesPage.tsx @@ -2,63 +2,49 @@ import { Helmet } from "react-helmet"; import { useTranslation } from "react-i18next"; import { ProjectPermissionCan } from "@app/components/permissions"; -import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context"; +import { PageHeader } from "@app/components/v2"; +import { ProjectPermissionActions, ProjectPermissionSub, useProjectPermission } from "@app/context"; -import { CaTab, CertificatesTab, PkiAlertsTab } from "./components"; - -enum TabSections { - Ca = "certificate-authorities", - Certificates = "certificates", - Alerting = "alerting" -} +import { PkiCollectionSection } from "../AlertingPage/components"; +import { CertificatesSection } from "./components"; export const CertificatesPage = () => { const { t } = useTranslation(); + const { permission } = useProjectPermission(); + + const canAccessPkiColl = permission.can( + ProjectPermissionActions.Read, + ProjectPermissionSub.PkiCollections + ); + const canAccessCerts = permission.can( + ProjectPermissionActions.Read, + ProjectPermissionSub.Certificates + ); + return (
{t("common.head-title", { title: "Certificates" })}
- - - - Certificates - Certificate Authorities - Alerting - - - - - - - - - - - - - - - - - + + {/* If both are false, the section does not render. This is to prevent duplicate banners. */} + {(canAccessCerts || canAccessPkiColl) && ( + + + + )} + + +
); diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/CaTab.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/CaTab.tsx deleted file mode 100644 index aadca4dfe..000000000 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/CaTab.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { motion } from "framer-motion"; - -import { CaSection } from "./components"; - -export const CaTab = () => { - return ( - - - - ); -}; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/index.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/index.tsx deleted file mode 100644 index 9e52be028..000000000 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CaTab/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { CaTab } from "./CaTab"; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateCertModal.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateCertModal.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateCertModal.tsx rename to frontend/src/pages/cert-manager/CertificatesPage/components/CertificateCertModal.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateContent.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateContent.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateContent.tsx rename to frontend/src/pages/cert-manager/CertificatesPage/components/CertificateContent.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateModal.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateModal.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateModal.tsx rename to frontend/src/pages/cert-manager/CertificatesPage/components/CertificateModal.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateRevocationModal.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRevocationModal.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateRevocationModal.tsx rename to frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRevocationModal.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateTemplateEnrollmentModal.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplateEnrollmentModal.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateTemplateEnrollmentModal.tsx rename to frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplateEnrollmentModal.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateTemplateModal.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplateModal.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateTemplateModal.tsx rename to frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplateModal.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateTemplatesSection.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplatesSection.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateTemplatesSection.tsx rename to frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplatesSection.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateTemplatesTable.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplatesTable.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateTemplatesTable.tsx rename to frontend/src/pages/cert-manager/CertificatesPage/components/CertificateTemplatesTable.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificatesSection.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesSection.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificatesSection.tsx rename to frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesSection.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/CertificatesTab.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/CertificatesTab.tsx deleted file mode 100644 index 0f74920ec..000000000 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/CertificatesTab.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { motion } from "framer-motion"; - -import { PkiCollectionSection } from "../PkiAlertsTab/components"; -// import { CertificateTemplatesSection } from "./components/CertificateTemplatesSection"; -import { CertificatesSection } from "./components"; - -export const CertificatesTab = () => { - return ( - - - {/* */} - - - ); -}; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/index.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/index.tsx deleted file mode 100644 index 7854a6f8b..000000000 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { CertificatesSection } from "./CertificatesSection"; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/index.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/index.tsx deleted file mode 100644 index 277134d56..000000000 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { CertificatesTab } from "./CertificatesTab"; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificatesTable.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.tsx similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificatesTable.tsx rename to frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.tsx diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificatesTable.utils.ts b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.utils.ts similarity index 100% rename from frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificatesTable.utils.ts rename to frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.utils.ts diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/PkiAlertsTab.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/PkiAlertsTab.tsx deleted file mode 100644 index 3a5a04345..000000000 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/PkiAlertsTab.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { motion } from "framer-motion"; - -import { PkiAlertsSection } from "./components"; - -export const PkiAlertsTab = () => { - return ( - - - - ); -}; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/index.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/index.tsx deleted file mode 100644 index 0acaf13d6..000000000 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/PkiAlertsTab/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { PkiAlertsTab } from "./PkiAlertsTab"; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/index.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/index.tsx index 851d403a0..7854a6f8b 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/index.tsx +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/index.tsx @@ -1,3 +1 @@ -export { CaTab } from "./CaTab"; -export { CertificatesTab } from "./CertificatesTab"; -export { PkiAlertsTab } from "./PkiAlertsTab"; +export { CertificatesSection } from "./CertificatesSection"; diff --git a/frontend/src/pages/cert-manager/PkiCollectionDetailsByIDPage/PkiCollectionDetailsByIDPage.tsx b/frontend/src/pages/cert-manager/PkiCollectionDetailsByIDPage/PkiCollectionDetailsByIDPage.tsx index 5cd8bf7c6..073cac6e8 100644 --- a/frontend/src/pages/cert-manager/PkiCollectionDetailsByIDPage/PkiCollectionDetailsByIDPage.tsx +++ b/frontend/src/pages/cert-manager/PkiCollectionDetailsByIDPage/PkiCollectionDetailsByIDPage.tsx @@ -22,7 +22,7 @@ import { PkiItemType } from "@app/hooks/api/pkiCollections/constants"; import { ProjectType } from "@app/hooks/api/workspace/types"; import { usePopUp } from "@app/hooks/usePopUp"; -import { PkiCollectionModal } from "../CertificatesPage/components/PkiAlertsTab/components/PkiCollectionModal"; +import { PkiCollectionModal } from "../AlertingPage/components/PkiCollectionModal"; import { PkiCollectionDetailsSection, PkiCollectionItemsSection } from "./components"; export const PkiCollectionPage = () => { diff --git a/frontend/src/pages/kms/KmipPage/components/KmipClientCertificateModal.tsx b/frontend/src/pages/kms/KmipPage/components/KmipClientCertificateModal.tsx index 4f8744682..81694e025 100644 --- a/frontend/src/pages/kms/KmipPage/components/KmipClientCertificateModal.tsx +++ b/frontend/src/pages/kms/KmipPage/components/KmipClientCertificateModal.tsx @@ -1,6 +1,6 @@ import { Modal, ModalContent } from "@app/components/v2"; import { KmipClientCertificate } from "@app/hooks/api/kmip/types"; -import { CertificateContent } from "@app/pages/cert-manager/CertificatesPage/components/CertificatesTab/components/CertificateContent"; +import { CertificateContent } from "@app/pages/cert-manager/CertificatesPage/components/CertificateContent"; type Props = { isOpen: boolean; diff --git a/frontend/src/pages/organization/SettingsPage/components/OrgEncryptionTab/ExternalKmsItem.tsx b/frontend/src/pages/organization/SettingsPage/components/OrgEncryptionTab/ExternalKmsItem.tsx new file mode 100644 index 000000000..d080b57c6 --- /dev/null +++ b/frontend/src/pages/organization/SettingsPage/components/OrgEncryptionTab/ExternalKmsItem.tsx @@ -0,0 +1,152 @@ +import { faAws, faGoogle } from "@fortawesome/free-brands-svg-icons"; +import { faCheck, faCopy, faEllipsis } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { twMerge } from "tailwind-merge"; + +import { createNotification } from "@app/components/notifications"; +import { OrgPermissionCan } from "@app/components/permissions/OrgPermissionCan"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger +} from "@app/components/v2/Dropdown"; +import { IconButton } from "@app/components/v2/IconButton"; +import { Td, Tr } from "@app/components/v2/Table"; +import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context/OrgPermissionContext"; +import { useToggle } from "@app/hooks"; +import { ExternalKmsProvider, KmsListEntry } from "@app/hooks/api/kms/types"; +import { SubscriptionPlan } from "@app/hooks/api/types"; +import { UsePopUpState } from "@app/hooks/usePopUp"; + +type Props = { + kms: KmsListEntry; + handlePopUpOpen: ( + popUpName: keyof UsePopUpState<["editExternalKms", "removeExternalKms", "upgradePlan"]>, + data?: { + kmsId?: string; + name?: string; + provider?: string; + } + ) => void; + subscription: SubscriptionPlan; +}; + +export const ExternalKmsItem = ({ kms, handlePopUpOpen, subscription }: Props) => { + const [isKmsIdCopied, { timedToggle: toggleKmsIdCopied }] = useToggle(false); + const [isKmsAliasCopied, { timedToggle: toggleKmsAliasCopied }] = useToggle(false); + + return ( + + + {kms.externalKms.provider === ExternalKmsProvider.Aws && } + {kms.externalKms.provider === ExternalKmsProvider.Gcp && ( + + )} +
{kms.externalKms.provider.toUpperCase()}
+ + +
+ {kms.name} + { + if (isKmsAliasCopied) { + return; + } + navigator.clipboard.writeText(kms.name); + createNotification({ + text: "KMS alias copied to clipboard", + type: "success" + }); + toggleKmsAliasCopied(2000); + }} + > + + +
+ + +
+ {kms.id} + { + if (isKmsIdCopied) { + return; + } + navigator.clipboard.writeText(kms.id); + createNotification({ + text: "KMS ID copied to clipboard", + type: "success" + }); + toggleKmsIdCopied(2000); + }} + > + + +
+ + + + +
+ +
+
+ + + {(isAllowed) => ( + { + e.stopPropagation(); + if (subscription && !subscription?.externalKms) { + handlePopUpOpen("upgradePlan"); + return; + } + + handlePopUpOpen("editExternalKms", { + kmsId: kms.id + }); + }} + > + Edit + + )} + + + {(isAllowed) => ( + { + e.stopPropagation(); + handlePopUpOpen("removeExternalKms", { + name: kms.name, + kmsId: kms.id, + provider: kms.externalKms.provider + }); + }} + > + Delete + + )} + + +
+ + + ); +}; diff --git a/frontend/src/pages/organization/SettingsPage/components/OrgEncryptionTab/OrgEncryptionTab.tsx b/frontend/src/pages/organization/SettingsPage/components/OrgEncryptionTab/OrgEncryptionTab.tsx index dc25b40af..8f1bd8e79 100644 --- a/frontend/src/pages/organization/SettingsPage/components/OrgEncryptionTab/OrgEncryptionTab.tsx +++ b/frontend/src/pages/organization/SettingsPage/components/OrgEncryptionTab/OrgEncryptionTab.tsx @@ -1,7 +1,5 @@ -import { faAws, faGoogle } from "@fortawesome/free-brands-svg-icons"; -import { faEllipsis, faLock, faPlus } from "@fortawesome/free-solid-svg-icons"; +import { faLock, faPlus } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { twMerge } from "tailwind-merge"; import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal"; import { createNotification } from "@app/components/notifications"; @@ -9,10 +7,6 @@ import { OrgPermissionCan } from "@app/components/permissions"; import { Button, DeleteActionModal, - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, EmptyState, Table, TableContainer, @@ -31,9 +25,9 @@ import { import { withPermission } from "@app/hoc"; import { usePopUp } from "@app/hooks"; import { useGetExternalKmsList, useRemoveExternalKms } from "@app/hooks/api"; -import { ExternalKmsProvider } from "@app/hooks/api/kms/types"; import { AddExternalKmsForm } from "./AddExternalKmsForm"; +import { ExternalKmsItem } from "./ExternalKmsItem"; import { UpdateExternalKmsForm } from "./UpdateExternalKmsForm"; export const OrgEncryptionTab = withPermission( @@ -102,6 +96,7 @@ export const OrgEncryptionTab = withPermission( Provider Alias + ID @@ -115,78 +110,12 @@ export const OrgEncryptionTab = withPermission( )} {!isExternalKmsListLoading && externalKmsList?.map((kms) => ( - - - {kms.externalKms.provider === ExternalKmsProvider.Aws && ( - - )} - {kms.externalKms.provider === ExternalKmsProvider.Gcp && ( - - )} -
{kms.externalKms.provider.toUpperCase()}
- - {kms.name} - - - -
- -
-
- - - {(isAllowed) => ( - { - e.stopPropagation(); - if (subscription && !subscription?.externalKms) { - handlePopUpOpen("upgradePlan"); - return; - } - - handlePopUpOpen("editExternalKms", { - kmsId: kms.id - }); - }} - > - Edit - - )} - - - {(isAllowed) => ( - { - e.stopPropagation(); - handlePopUpOpen("removeExternalKms", { - name: kms.name, - kmsId: kms.id, - provider: kms.externalKms.provider - }); - }} - > - Delete - - )} - - -
- - + ))} diff --git a/frontend/src/pages/secret-manager/SettingsPage/components/DeleteProjectSection/DeleteProjectSection.tsx b/frontend/src/pages/secret-manager/SettingsPage/components/DeleteProjectSection/DeleteProjectSection.tsx index 2f11523c4..ffb9e93fc 100644 --- a/frontend/src/pages/secret-manager/SettingsPage/components/DeleteProjectSection/DeleteProjectSection.tsx +++ b/frontend/src/pages/secret-manager/SettingsPage/components/DeleteProjectSection/DeleteProjectSection.tsx @@ -3,7 +3,7 @@ import { useNavigate } from "@tanstack/react-router"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; -import { Button, DeleteActionModal } from "@app/components/v2"; +import { Button, DeleteActionModal, Tooltip } from "@app/components/v2"; import { LeaveProjectModal } from "@app/components/v2/LeaveProjectModal"; import { ProjectPermissionActions, @@ -142,16 +142,22 @@ export const DeleteProjectSection = () => {
{(isAllowed) => ( - + + )} {!isOnlyAdminMember && ( diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts index e3ab6df7d..69186b45d 100644 --- a/frontend/src/routeTree.gen.ts +++ b/frontend/src/routeTree.gen.ts @@ -92,6 +92,8 @@ import { Route as kmsOverviewPageRouteImport } from './pages/kms/OverviewPage/ro import { Route as kmsKmipPageRouteImport } from './pages/kms/KmipPage/route' import { Route as certManagerSettingsPageRouteImport } from './pages/cert-manager/SettingsPage/route' import { Route as certManagerCertificatesPageRouteImport } from './pages/cert-manager/CertificatesPage/route' +import { Route as certManagerCertificateAuthoritiesPageRouteImport } from './pages/cert-manager/CertificateAuthoritiesPage/route' +import { Route as certManagerAlertingPageRouteImport } from './pages/cert-manager/AlertingPage/route' import { Route as projectRoleDetailsBySlugPageRouteSshImport } from './pages/project/RoleDetailsBySlugPage/route-ssh' import { Route as projectMemberDetailsByIDPageRouteSshImport } from './pages/project/MemberDetailsByIDPage/route-ssh' import { Route as projectIdentityDetailsByIDPageRouteSshImport } from './pages/project/IdentityDetailsByIDPage/route-ssh' @@ -894,6 +896,20 @@ const certManagerCertificatesPageRouteRoute = getParentRoute: () => certManagerLayoutRoute, } as any) +const certManagerCertificateAuthoritiesPageRouteRoute = + certManagerCertificateAuthoritiesPageRouteImport.update({ + id: '/certificate-authorities', + path: '/certificate-authorities', + getParentRoute: () => certManagerLayoutRoute, + } as any) + +const certManagerAlertingPageRouteRoute = + certManagerAlertingPageRouteImport.update({ + id: '/alerting', + path: '/alerting', + getParentRoute: () => certManagerLayoutRoute, + } as any) + const projectRoleDetailsBySlugPageRouteSshRoute = projectRoleDetailsBySlugPageRouteSshImport.update({ id: '/roles/$roleSlug', @@ -2104,6 +2120,20 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof sshLayoutImport parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutSshProjectIdImport } + '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/alerting': { + id: '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/alerting' + path: '/alerting' + fullPath: '/cert-manager/$projectId/alerting' + preLoaderRoute: typeof certManagerAlertingPageRouteImport + parentRoute: typeof certManagerLayoutImport + } + '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-authorities': { + id: '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-authorities' + path: '/certificate-authorities' + fullPath: '/cert-manager/$projectId/certificate-authorities' + preLoaderRoute: typeof certManagerCertificateAuthoritiesPageRouteImport + parentRoute: typeof certManagerLayoutImport + } '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/overview': { id: '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/overview' path: '/overview' @@ -3119,6 +3149,8 @@ const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteWithChildren = ) interface certManagerLayoutRouteChildren { + certManagerAlertingPageRouteRoute: typeof certManagerAlertingPageRouteRoute + certManagerCertificateAuthoritiesPageRouteRoute: typeof certManagerCertificateAuthoritiesPageRouteRoute certManagerCertificatesPageRouteRoute: typeof certManagerCertificatesPageRouteRoute certManagerSettingsPageRouteRoute: typeof certManagerSettingsPageRouteRoute projectAccessControlPageRouteCertManagerRoute: typeof projectAccessControlPageRouteCertManagerRoute @@ -3130,6 +3162,9 @@ interface certManagerLayoutRouteChildren { } const certManagerLayoutRouteChildren: certManagerLayoutRouteChildren = { + certManagerAlertingPageRouteRoute: certManagerAlertingPageRouteRoute, + certManagerCertificateAuthoritiesPageRouteRoute: + certManagerCertificateAuthoritiesPageRouteRoute, certManagerCertificatesPageRouteRoute: certManagerCertificatesPageRouteRoute, certManagerSettingsPageRouteRoute: certManagerSettingsPageRouteRoute, projectAccessControlPageRouteCertManagerRoute: @@ -3794,6 +3829,8 @@ export interface FileRoutesByFullPath { '/organization/secret-manager/overview': typeof organizationSecretManagerOverviewPageRouteRoute '/organization/secret-sharing/settings': typeof organizationSecretSharingSettingsPageRouteRoute '/organization/ssh/overview': typeof organizationSshOverviewPageRouteRoute + '/cert-manager/$projectId/alerting': typeof certManagerAlertingPageRouteRoute + '/cert-manager/$projectId/certificate-authorities': typeof certManagerCertificateAuthoritiesPageRouteRoute '/cert-manager/$projectId/overview': typeof certManagerCertificatesPageRouteRoute '/cert-manager/$projectId/settings': typeof certManagerSettingsPageRouteRoute '/kms/$projectId/kmip': typeof kmsKmipPageRouteRoute @@ -3969,6 +4006,8 @@ export interface FileRoutesByTo { '/organization/secret-manager/overview': typeof organizationSecretManagerOverviewPageRouteRoute '/organization/secret-sharing/settings': typeof organizationSecretSharingSettingsPageRouteRoute '/organization/ssh/overview': typeof organizationSshOverviewPageRouteRoute + '/cert-manager/$projectId/alerting': typeof certManagerAlertingPageRouteRoute + '/cert-manager/$projectId/certificate-authorities': typeof certManagerCertificateAuthoritiesPageRouteRoute '/cert-manager/$projectId/overview': typeof certManagerCertificatesPageRouteRoute '/cert-manager/$projectId/settings': typeof certManagerSettingsPageRouteRoute '/kms/$projectId/kmip': typeof kmsKmipPageRouteRoute @@ -4160,6 +4199,8 @@ export interface FileRoutesById { '/_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/ssh/$projectId/_ssh-layout': typeof sshLayoutRouteWithChildren + '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/alerting': typeof certManagerAlertingPageRouteRoute + '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-authorities': typeof certManagerCertificateAuthoritiesPageRouteRoute '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/overview': typeof certManagerCertificatesPageRouteRoute '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/settings': typeof certManagerSettingsPageRouteRoute '/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/kmip': typeof kmsKmipPageRouteRoute @@ -4344,6 +4385,8 @@ export interface FileRouteTypes { | '/organization/secret-manager/overview' | '/organization/secret-sharing/settings' | '/organization/ssh/overview' + | '/cert-manager/$projectId/alerting' + | '/cert-manager/$projectId/certificate-authorities' | '/cert-manager/$projectId/overview' | '/cert-manager/$projectId/settings' | '/kms/$projectId/kmip' @@ -4518,6 +4561,8 @@ export interface FileRouteTypes { | '/organization/secret-manager/overview' | '/organization/secret-sharing/settings' | '/organization/ssh/overview' + | '/cert-manager/$projectId/alerting' + | '/cert-manager/$projectId/certificate-authorities' | '/cert-manager/$projectId/overview' | '/cert-manager/$projectId/settings' | '/kms/$projectId/kmip' @@ -4707,6 +4752,8 @@ export interface FileRouteTypes { | '/_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/ssh/$projectId/_ssh-layout' + | '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/alerting' + | '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-authorities' | '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/overview' | '/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/settings' | '/_authenticate/_inject-org-details/_org-layout/kms/$projectId/_kms-layout/kmip' @@ -5222,6 +5269,8 @@ export const routeTree = rootRoute "filePath": "cert-manager/layout.tsx", "parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId", "children": [ + "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/alerting", + "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-authorities", "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/overview", "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/settings", "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/access-management", @@ -5277,6 +5326,14 @@ export const routeTree = rootRoute "/_authenticate/_inject-org-details/_org-layout/ssh/$projectId/_ssh-layout/roles/$roleSlug" ] }, + "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/alerting": { + "filePath": "cert-manager/AlertingPage/route.tsx", + "parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout" + }, + "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/certificate-authorities": { + "filePath": "cert-manager/CertificateAuthoritiesPage/route.tsx", + "parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout" + }, "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout/overview": { "filePath": "cert-manager/CertificatesPage/route.tsx", "parent": "/_authenticate/_inject-org-details/_org-layout/cert-manager/$projectId/_cert-manager-layout" diff --git a/frontend/src/routes.ts b/frontend/src/routes.ts index d6793ea1a..6c5c2832e 100644 --- a/frontend/src/routes.ts +++ b/frontend/src/routes.ts @@ -282,6 +282,8 @@ const secretManagerIntegrationsRedirect = route("/integrations", [ const certManagerRoutes = route("/cert-manager/$projectId", [ layout("cert-manager-layout", "cert-manager/layout.tsx", [ route("/overview", "cert-manager/CertificatesPage/route.tsx"), + route("/certificate-authorities", "cert-manager/CertificateAuthoritiesPage/route.tsx"), + route("/alerting", "cert-manager/AlertingPage/route.tsx"), route("/ca/$caId", "cert-manager/CertAuthDetailsByIDPage/route.tsx"), route("/pki-collections/$collectionId", "cert-manager/PkiCollectionDetailsByIDPage/routes.tsx"), route("/settings", "cert-manager/SettingsPage/route.tsx"),