From b13365ecf59cb29c53486e0b515a8d3dec6c4a30 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:39:29 +0100 Subject: [PATCH 01/11] Feat: Written API explanations --- backend/src/lib/api-docs/constants.ts | 286 ++++++++++++++++++++++++++ backend/src/lib/api-docs/index.ts | 1 + 2 files changed, 287 insertions(+) create mode 100644 backend/src/lib/api-docs/constants.ts create mode 100644 backend/src/lib/api-docs/index.ts diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts new file mode 100644 index 0000000000..6f5cc22963 --- /dev/null +++ b/backend/src/lib/api-docs/constants.ts @@ -0,0 +1,286 @@ +export const IDENTITIES = { + CREATE: { + name: "The name of the identity to create.", + organizationId: "The organization ID to which the identity belongs.", + role: "The role of the identity. Possible values are 'no-access', 'member', and 'admin'." + }, + UPDATE: { + identityId: "The ID of the identity to update.", + name: "The new name of the identity.", + role: "The new role of the identity." + }, + DELETE: { + identityId: "The ID of the identity to delete." + } +} as const; + +export const UNIVERSAL_AUTH = { + LOGIN: { + clientId: "Your Machine Identity Client ID.", + clientSecret: "Your Machine Identity Client Secret." + }, + ATTACH: { + identityId: "The ID of the identity to attach the configuration onto.", + clientSecretTrustedIps: + "A list of IPs or CIDR ranges that the Client Secret can be used from together with the Client ID to get back an access token. You can use 0.0.0.0/0, to allow usage from any network address.", + accessTokenTrustedIps: + "A list of IPs or CIDR ranges that access tokens can be used from. You can use 0.0.0.0/0, to allow usage from any network address.", + accessTokenTTL: "The lifetime for an access token in seconds. This value will be referenced at renewal time.", + accessTokenMaxTTL: + "The maximum lifetime for an access token in seconds. This value will be referenced at renewal time.", + accessTokenNumUsesLimit: + "The maximum number of times that an access token can be used; a value of 0 implies infinite number of uses." + }, + RETRIEVE: { + identityId: "The ID of the identity to retrieve." + }, + UPDATE: { + identityId: "The ID of the identity to update.", + clientSecretTrustedIps: "The new list of IPs or CIDR ranges that the Client Secret can be used from.", + accessTokenTrustedIps: "The new list of IPs or CIDR ranges that access tokens can be used from.", + accessTokenTTL: "The new lifetime for an access token in seconds.", + accessTokenMaxTTL: "The new maximum lifetime for an access token in seconds.", + accessTokenNumUsesLimit: "The new maximum number of times that an access token can be used." + }, + CREATE_CLIENT_SECRET: { + identityId: "The ID of the identity to create a client secret for.", + description: "The description of the client secret.", + numUsesLimit: + "The maximum number of times that the client secret can be used; a value of 0 implies infinite number of uses.", + ttl: "The lifetime for the client secret in seconds." + }, + LIST_CLIENT_SECRETS: { + identityId: "The ID of the identity to list client secrets for." + }, + REVOKE_CLIENT_SECRET: { + identityId: "The ID of the identity to revoke the client secret from.", + clientSecretId: "The ID of the client secret to revoke." + }, + RENEW_ACCESS_TOKEN: { + accessToken: "The access token to renew." + } +} as const; + +export const ORGANIZATIONS = { + LIST_USER_MEMBERSHIPS: { + organizationId: "The ID of the organization to get memberships from." + }, + UPDATE_USER_MEMBERSHIP: { + organizationId: "The ID of the organization to update the membership for.", + membershipId: "The ID of the membership to update.", + role: "The new role of the membership." + }, + DELETE_USER_MEMBERSHIP: { + organizationId: "The ID of the organization to delete the membership from.", + membershipId: "The ID of the membership to delete." + }, + LIST_IDENTITY_MEMBERSHIPS: { + orgId: "The ID of the organization to get identity memberships from." + }, + GET_PROJECTS: { + organizationId: "The ID of the organization to get projects from." + } +} as const; + +export const PROJECTS = { + CREATE: { + organizationId: "The ID of the organization to create the project in.", + projectName: "The name of the project to create.", + slug: "An optional slug for the project." + }, + DELETE: { + workspaceId: "The ID of the project to delete." + }, + GET: { + workspaceId: "The ID of the project." + }, + UPDATE: { + workspaceId: "The ID of the project to update.", + name: "The new name of the project.", + autoCapitalization: "Disable or enable auto-capitalization for the project." + }, + INVITE_MEMBER: { + projectId: "The ID of the project to invite the member to.", + emails: "A list of organization member emails to invite to the project.", + usernames: "A list of usernames to invite to the project." + }, + REMOVE_MEMBER: { + projectId: "The ID of the project to remove the member from.", + emails: "A list of organization member emails to remove from the project.", + usernames: "A list of usernames to remove from the project." + }, + GET_USER_MEMBERSHIPS: { + workspaceId: "The ID of the project to get memberships from." + }, + UPDATE_USER_MEMBERSHIP: { + workspaceId: "The ID of the project to update the membership for.", + membershipId: "The ID of the membership to update.", + roles: "A list of roles to update the membership to." + }, + LIST_IDENTITY_MEMBERSHIPS: { + projectId: "The ID of the project to get identity memberships from." + }, + UPDATE_IDENTITY_MEMBERSHIP: { + projectId: "The ID of the project to update the identity membership for.", + identityId: "The ID of the identity to update the membership for.", + roles: "A list of roles to update the membership to." + }, + DELETE_IDENTITY_MEMBERSHIP: { + projectId: "The ID of the project to delete the identity membership from.", + identityId: "The ID of the identity to delete the membership from." + }, + GET_KEY: { + workspaceId: "The ID of the project to get the key from." + }, + GET_SNAPSHOTS: { + workspaceId: "The ID of the project to get snapshots from.", + environment: "The environment to get snapshots from.", + path: "The secret path to get snapshots from.", + offset: "The offset to start from. If you enter 10, it will start from the 10th snapshot.", + limit: "The number of snapshots to return." + }, + ROLLBACK_TO_SNAPSHOT: { + secretSnapshotId: "The ID of the snapshot to rollback to." + } +} as const; + +export const ENVIRONMENTS = { + CREATE: { + workspaceId: "The ID of the project to create the environment in.", + name: "The name of the environment to create.", + slug: "The slug of the environment to create." + }, + UPDATE: { + workspaceId: "The ID of the project to update the environment in.", + id: "The ID of the environment to update.", + name: "The new name of the environment.", + slug: "The new slug of the environment.", + position: "The new position of the environment. The lowest number will be displayed as the first environment." + }, + DELETE: { + workspaceId: "The ID of the project to delete the environment from.", + id: "The ID of the environment to delete." + } +} as const; + +export const FOLDERS = { + LIST: { + workspaceId: "The ID of the project to list folders from.", + environment: "The slug of the environment to list folders from.", + path: "The path to list folders from.", + directory: "The directory to list folders from. (Deprecated in favor of path)" + }, + CREATE: { + workspaceId: "The ID of the project to create the folder in.", + environment: "The slug of the environment to create the folder in.", + name: "The name of the folder to create.", + path: "The path of the folder to create.", + directory: "The directory of the folder to create. (Deprecated in favor of path)" + }, + UPDATE: { + folderId: "The ID of the folder to update.", + environment: "The slug of the environment where the folder is located.", + name: "The new name of the folder.", + path: "The path of the folder to update.", + directory: "The new directory of the folder to update. (Deprecated in favor of path)", + workspaceId: "The ID of the project where the folder is located." + }, + DELETE: { + folderIdOrName: "The ID or name of the folder to delete.", + workspaceId: "The ID of the project to delete the folder from.", + environment: "The slug of the environment where the folder is located.", + directory: "The directory of the folder to delete. (Deprecated in favor of path)", + path: "The path of the folder to delete." + } +} as const; + +export const RAW_SECRETS = { + LIST: { + workspaceId: "The ID of the project to list secrets from.", + environment: "The slug of the environment to list secrets from.", + secretPath: "The secret path to list secrets from.", + includeImports: "Weather to include imported secrets or not." + }, + CREATE: { + secretName: "The name of the secret to create.", + environment: "The slug of the environment to create the secret in.", + secretComment: "Attach a comment to the secret.", + secretPath: "The path to create the secret in.", + secretValue: "The value of the secret to create.", + skipMultilineEncoding: "Skip multiline encoding for the secret value.", + type: "The type of the secret to create.", + workspaceId: "The ID of the project to create the secret in." + }, + GET: { + secretName: "The name of the secret to get.", + workspaceId: "The ID of the project to get the secret from.", + environment: "The slug of the environment to get the secret from.", + secretPath: "The path of the secret to get.", + version: "The version of the secret to get.", + type: "The type of the secret to get.", + includeImports: "Weather to include imported secrets or not." + }, + UPDATE: { + secretName: "The name of the secret to update.", + environment: "The slug of the environment where the secret is located.", + secretPath: "The path of the secret to update", + secretValue: "The new value of the secret.", + skipMultilineEncoding: "Skip multiline encoding for the secret value.", + type: "The type of the secret to update.", + workspaceId: "The ID of the project to update the secret in." + }, + DELETE: { + secretName: "The name of the secret to delete.", + environment: "The slug of the environment where the secret is located.", + secretPath: "The path of the secret.", + type: "The type of the secret to delete.", + workspaceId: "The ID of the project where the secret is located." + } +} as const; + +export const SECRET_IMPORTS = { + LIST: { + workspaceId: "The ID of the project to list secret imports from.", + environment: "The slug of the environment to list secret imports from.", + path: "The path to list secret imports from." + }, + CREATE: { + environment: "The slug of the environment to import into.", + path: "The path to import into.", + workspaceId: "The ID of the project you are working in.", + import: { + environment: "The slug of the environment to import from.", + path: "The path to import from." + } + }, + UPDATE: { + secretImportId: "The ID of the secret import to update.", + environment: "The slug of the environment where the secret import is located.", + import: { + environment: "The new environment slug to import from.", + path: "The new path to import from.", + position: "The new position of the secret import. The lowest number will be displayed as the first import." + }, + path: "The path of the secret import to update.", + workspaceId: "The ID of the project where the secret import is located." + }, + DELETE: { + workspaceId: "The ID of the project to delete the secret import from.", + secretImportId: "The ID of the secret import to delete.", + environment: "The slug of the environment where the secret import is located.", + path: "The path of the secret import to delete." + } +} as const; + +export const AUDIT_LOGS = { + EXPORT: { + workspaceId: "The ID of the project to export audit logs from.", + eventType: "The type of the event to export.", + userAgentType: "Choose which consuming application to export audit logs for.", + startDate: "The date to start the export from.", + endDate: "The date to end the export at.", + offset: "The offset to start from. If you enter 10, it will start from the 10th audit log.", + limit: "The number of audit logs to return.", + actor: "The actor to filter the audit logs by." + } +} as const; diff --git a/backend/src/lib/api-docs/index.ts b/backend/src/lib/api-docs/index.ts new file mode 100644 index 0000000000..b04bfcf75e --- /dev/null +++ b/backend/src/lib/api-docs/index.ts @@ -0,0 +1 @@ +export * from "./constants"; From b4f372f883861e1048679ba741b90c76d1ac7477 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:40:08 +0100 Subject: [PATCH 02/11] Fix: Delete folder docs page not rendering --- docs/api-reference/endpoints/folders/delete.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-reference/endpoints/folders/delete.mdx b/docs/api-reference/endpoints/folders/delete.mdx index dc73a41da0..a106cc2eba 100644 --- a/docs/api-reference/endpoints/folders/delete.mdx +++ b/docs/api-reference/endpoints/folders/delete.mdx @@ -1,4 +1,4 @@ --- title: "Delete" -openapi: "DELETE /api/v1/folders/{folderId}" +openapi: "DELETE /api/v1/folders/{folderIdOrName}" --- From bab8f95fde580f4e29b8bc43de2328b1a6fab736 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:40:38 +0100 Subject: [PATCH 03/11] Feat: Added descriptions to all public API endpoints --- backend/src/ee/routes/v1/project-router.ts | 27 +++--- backend/src/ee/routes/v1/snapshot-router.ts | 3 +- .../routes/v1/identity-access-token-router.ts | 4 +- .../src/server/routes/v1/identity-router.ts | 15 ++-- backend/src/server/routes/v1/identity-ua.ts | 60 +++++++++----- .../server/routes/v1/project-env-router.ts | 21 ++--- .../routes/v1/project-membership-router.ts | 8 +- .../src/server/routes/v1/project-router.ts | 16 ++-- .../server/routes/v1/secret-folder-router.ts | 42 +++++----- .../server/routes/v1/secret-import-router.ts | 40 ++++----- .../server/routes/v2/identity-org-router.ts | 3 +- .../routes/v2/identity-project-router.ts | 12 +-- .../server/routes/v2/organization-router.ts | 17 ++-- .../routes/v2/project-membership-router.ts | 13 +-- .../src/server/routes/v2/project-router.ts | 10 ++- backend/src/server/routes/v3/secret-router.ts | 82 ++++++++++++------- 16 files changed, 223 insertions(+), 150 deletions(-) diff --git a/backend/src/ee/routes/v1/project-router.ts b/backend/src/ee/routes/v1/project-router.ts index cfcecb8f0c..6064483723 100644 --- a/backend/src/ee/routes/v1/project-router.ts +++ b/backend/src/ee/routes/v1/project-router.ts @@ -2,6 +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 { removeTrailingSlash } from "@app/lib/fn"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -19,13 +20,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - workspaceId: z.string().trim() + workspaceId: z.string().trim().describe(PROJECTS.GET_SNAPSHOTS.workspaceId) }), querystring: z.object({ - environment: z.string().trim(), - path: z.string().trim().default("/").transform(removeTrailingSlash), - offset: z.coerce.number().default(0), - limit: z.coerce.number().default(20) + environment: z.string().trim().describe(PROJECTS.GET_SNAPSHOTS.environment), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(PROJECTS.GET_SNAPSHOTS.path), + offset: z.coerce.number().default(0).describe(PROJECTS.GET_SNAPSHOTS.offset), + limit: z.coerce.number().default(20).describe(PROJECTS.GET_SNAPSHOTS.limit) }), response: { 200: z.object({ @@ -89,16 +90,16 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - workspaceId: z.string().trim() + workspaceId: z.string().trim().describe(AUDIT_LOGS.EXPORT.workspaceId) }), querystring: z.object({ - eventType: z.nativeEnum(EventType).optional(), - userAgentType: z.nativeEnum(UserAgentType).optional(), - startDate: z.string().datetime().optional(), - endDate: z.string().datetime().optional(), - offset: z.coerce.number().default(0), - limit: z.coerce.number().default(20), - actor: z.string().optional() + eventType: z.nativeEnum(EventType).optional().describe(AUDIT_LOGS.EXPORT.eventType), + userAgentType: z.nativeEnum(UserAgentType).optional().describe(AUDIT_LOGS.EXPORT.userAgentType), + startDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.startDate), + endDate: z.string().datetime().optional().describe(AUDIT_LOGS.EXPORT.endDate), + offset: z.coerce.number().default(0).describe(AUDIT_LOGS.EXPORT.offset), + limit: z.coerce.number().default(20).describe(AUDIT_LOGS.EXPORT.limit), + actor: z.string().optional().describe(AUDIT_LOGS.EXPORT.actor) }), response: { 200: z.object({ diff --git a/backend/src/ee/routes/v1/snapshot-router.ts b/backend/src/ee/routes/v1/snapshot-router.ts index 0b858255f7..79161bfd30 100644 --- a/backend/src/ee/routes/v1/snapshot-router.ts +++ b/backend/src/ee/routes/v1/snapshot-router.ts @@ -1,6 +1,7 @@ import { z } from "zod"; import { SecretSnapshotsSchema, SecretTagsSchema, SecretVersionsSchema } from "@app/db/schemas"; +import { PROJECTS } from "@app/lib/api-docs"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -65,7 +66,7 @@ export const registerSnapshotRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - secretSnapshotId: z.string().trim() + secretSnapshotId: z.string().trim().describe(PROJECTS.ROLLBACK_TO_SNAPSHOT.secretSnapshotId) }), response: { 200: z.object({ 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 78112f8962..5cd0b27a16 100644 --- a/backend/src/server/routes/v1/identity-access-token-router.ts +++ b/backend/src/server/routes/v1/identity-access-token-router.ts @@ -1,5 +1,7 @@ import { z } from "zod"; +import { UNIVERSAL_AUTH } from "@app/lib/api-docs"; + export const registerIdentityAccessTokenRouter = async (server: FastifyZodProvider) => { server.route({ url: "/token/renew", @@ -7,7 +9,7 @@ export const registerIdentityAccessTokenRouter = async (server: FastifyZodProvid schema: { description: "Renew access token", body: z.object({ - accessToken: z.string().trim() + accessToken: z.string().trim().describe(UNIVERSAL_AUTH.RENEW_ACCESS_TOKEN.accessToken) }), response: { 200: z.object({ diff --git a/backend/src/server/routes/v1/identity-router.ts b/backend/src/server/routes/v1/identity-router.ts index 0ec27a98bc..ac389b4784 100644 --- a/backend/src/server/routes/v1/identity-router.ts +++ b/backend/src/server/routes/v1/identity-router.ts @@ -2,6 +2,7 @@ import { z } from "zod"; import { IdentitiesSchema, OrgMembershipRole } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { IDENTITIES } from "@app/lib/api-docs"; import { getTelemetryDistinctId } from "@app/server/lib/telemetry"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -20,9 +21,9 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => { } ], body: z.object({ - name: z.string().trim(), - organizationId: z.string().trim(), - role: z.string().trim().min(1).default(OrgMembershipRole.NoAccess) + name: z.string().trim().describe(IDENTITIES.CREATE.name), + organizationId: z.string().trim().describe(IDENTITIES.CREATE.organizationId), + role: z.string().trim().min(1).default(OrgMembershipRole.NoAccess).describe(IDENTITIES.CREATE.role) }), response: { 200: z.object({ @@ -78,11 +79,11 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - identityId: z.string() + identityId: z.string().describe(IDENTITIES.UPDATE.identityId) }), body: z.object({ - name: z.string().trim().optional(), - role: z.string().trim().min(1).optional() + name: z.string().trim().optional().describe(IDENTITIES.UPDATE.name), + role: z.string().trim().min(1).optional().describe(IDENTITIES.UPDATE.role) }), response: { 200: z.object({ @@ -127,7 +128,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - identityId: z.string() + identityId: z.string().describe(IDENTITIES.DELETE.identityId) }), response: { 200: z.object({ diff --git a/backend/src/server/routes/v1/identity-ua.ts b/backend/src/server/routes/v1/identity-ua.ts index 4499a88e7c..6146fa2422 100644 --- a/backend/src/server/routes/v1/identity-ua.ts +++ b/backend/src/server/routes/v1/identity-ua.ts @@ -2,6 +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 { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; import { TIdentityTrustedIp } from "@app/services/identity/identity-types"; @@ -26,8 +27,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { schema: { description: "Login with Universal Auth", body: z.object({ - clientId: z.string().trim(), - clientSecret: z.string().trim() + clientId: z.string().trim().describe(UNIVERSAL_AUTH.LOGIN.clientId), + clientSecret: z.string().trim().describe(UNIVERSAL_AUTH.LOGIN.clientSecret) }), response: { 200: z.object({ @@ -76,7 +77,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - identityId: z.string().trim() + identityId: z.string().trim().describe(UNIVERSAL_AUTH.ATTACH.identityId) }), body: z.object({ clientSecretTrustedIps: z @@ -85,14 +86,16 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { }) .array() .min(1) - .default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]), + .default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]) + .describe(UNIVERSAL_AUTH.ATTACH.clientSecretTrustedIps), accessTokenTrustedIps: z .object({ ipAddress: z.string().trim() }) .array() .min(1) - .default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]), + .default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]) + .describe(UNIVERSAL_AUTH.ATTACH.accessTokenTrustedIps), accessTokenTTL: z .number() .int() @@ -100,15 +103,22 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { .refine((value) => value !== 0, { message: "accessTokenTTL must have a non zero number" }) - .default(2592000), + .default(2592000) + .describe(UNIVERSAL_AUTH.ATTACH.accessTokenTTL), // 30 days accessTokenMaxTTL: z .number() .int() .refine((value) => value !== 0, { message: "accessTokenMaxTTL must have a non zero number" }) - .default(2592000), // 30 days - accessTokenNumUsesLimit: z.number().int().min(0).default(0) + .default(2592000) + .describe(UNIVERSAL_AUTH.ATTACH.accessTokenMaxTTL), // 30 days + accessTokenNumUsesLimit: z + .number() + .int() + .min(0) + .default(0) + .describe(UNIVERSAL_AUTH.ATTACH.accessTokenNumUsesLimit) }), response: { 200: z.object({ @@ -156,7 +166,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - identityId: z.string() + identityId: z.string().describe(UNIVERSAL_AUTH.UPDATE.identityId) }), body: z.object({ clientSecretTrustedIps: z @@ -165,16 +175,23 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { }) .array() .min(1) - .optional(), + .optional() + .describe(UNIVERSAL_AUTH.UPDATE.clientSecretTrustedIps), accessTokenTrustedIps: z .object({ ipAddress: z.string().trim() }) .array() .min(1) - .optional(), - accessTokenTTL: z.number().int().min(0).optional(), - accessTokenNumUsesLimit: z.number().int().min(0).optional(), + .optional() + .describe(UNIVERSAL_AUTH.UPDATE.accessTokenTrustedIps), + accessTokenTTL: z.number().int().min(0).optional().describe(UNIVERSAL_AUTH.UPDATE.accessTokenTTL), + accessTokenNumUsesLimit: z + .number() + .int() + .min(0) + .optional() + .describe(UNIVERSAL_AUTH.UPDATE.accessTokenNumUsesLimit), accessTokenMaxTTL: z .number() .int() @@ -182,6 +199,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { message: "accessTokenMaxTTL must have a non zero number" }) .optional() + .describe(UNIVERSAL_AUTH.UPDATE.accessTokenMaxTTL) }), response: { 200: z.object({ @@ -230,7 +248,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - identityId: z.string() + identityId: z.string().describe(UNIVERSAL_AUTH.RETRIEVE.identityId) }), response: { 200: z.object({ @@ -273,12 +291,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - identityId: z.string() + identityId: z.string().describe(UNIVERSAL_AUTH.CREATE_CLIENT_SECRET.identityId) }), body: z.object({ - description: z.string().trim().default(""), - numUsesLimit: z.number().min(0).default(0), - ttl: z.number().min(0).default(0) + description: z.string().trim().default("").describe(UNIVERSAL_AUTH.CREATE_CLIENT_SECRET.description), + numUsesLimit: z.number().min(0).default(0).describe(UNIVERSAL_AUTH.CREATE_CLIENT_SECRET.numUsesLimit), + ttl: z.number().min(0).default(0).describe(UNIVERSAL_AUTH.CREATE_CLIENT_SECRET.ttl) }), response: { 200: z.object({ @@ -324,7 +342,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - identityId: z.string() + identityId: z.string().describe(UNIVERSAL_AUTH.LIST_CLIENT_SECRETS.identityId) }), response: { 200: z.object({ @@ -366,8 +384,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - identityId: z.string(), - clientSecretId: z.string() + identityId: z.string().describe(UNIVERSAL_AUTH.REVOKE_CLIENT_SECRET.identityId), + clientSecretId: z.string().describe(UNIVERSAL_AUTH.REVOKE_CLIENT_SECRET.clientSecretId) }), response: { 200: z.object({ diff --git a/backend/src/server/routes/v1/project-env-router.ts b/backend/src/server/routes/v1/project-env-router.ts index b93ffe9283..cb5be173e7 100644 --- a/backend/src/server/routes/v1/project-env-router.ts +++ b/backend/src/server/routes/v1/project-env-router.ts @@ -2,6 +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 { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -18,11 +19,11 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - workspaceId: z.string().trim() + workspaceId: z.string().trim().describe(ENVIRONMENTS.CREATE.workspaceId) }), body: z.object({ - name: z.string().trim(), - slug: z.string().trim() + name: z.string().trim().describe(ENVIRONMENTS.CREATE.name), + slug: z.string().trim().describe(ENVIRONMENTS.CREATE.slug) }), response: { 200: z.object({ @@ -73,13 +74,13 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - workspaceId: z.string().trim(), - id: z.string().trim() + workspaceId: z.string().trim().describe(ENVIRONMENTS.UPDATE.workspaceId), + id: z.string().trim().describe(ENVIRONMENTS.UPDATE.id) }), body: z.object({ - slug: z.string().trim().optional(), - name: z.string().trim().optional(), - position: z.number().optional() + slug: z.string().trim().optional().describe(ENVIRONMENTS.UPDATE.slug), + name: z.string().trim().optional().describe(ENVIRONMENTS.UPDATE.name), + position: z.number().optional().describe(ENVIRONMENTS.UPDATE.position) }), response: { 200: z.object({ @@ -136,8 +137,8 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - workspaceId: z.string().trim(), - id: z.string().trim() + workspaceId: z.string().trim().describe(ENVIRONMENTS.DELETE.workspaceId), + id: z.string().trim().describe(ENVIRONMENTS.DELETE.id) }), response: { 200: z.object({ diff --git a/backend/src/server/routes/v1/project-membership-router.ts b/backend/src/server/routes/v1/project-membership-router.ts index 999a5d0256..aece95a5d4 100644 --- a/backend/src/server/routes/v1/project-membership-router.ts +++ b/backend/src/server/routes/v1/project-membership-router.ts @@ -9,6 +9,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 { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; import { ProjectUserMembershipTemporaryMode } from "@app/services/project-membership/project-membership-types"; @@ -26,7 +27,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider } ], params: z.object({ - workspaceId: z.string().trim() + workspaceId: z.string().trim().describe(PROJECTS.GET_USER_MEMBERSHIPS.workspaceId) }), response: { 200: z.object({ @@ -134,8 +135,8 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider } ], params: z.object({ - workspaceId: z.string().trim(), - membershipId: z.string().trim() + workspaceId: z.string().trim().describe(PROJECTS.UPDATE_USER_MEMBERSHIP.workspaceId), + membershipId: z.string().trim().describe(PROJECTS.UPDATE_USER_MEMBERSHIP.membershipId) }), body: z.object({ roles: z @@ -156,6 +157,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider ) .min(1) .refine((data) => data.some(({ isTemporary }) => !isTemporary), "At least long lived role is required") + .describe(PROJECTS.UPDATE_USER_MEMBERSHIP.roles) }), response: { 200: z.object({ diff --git a/backend/src/server/routes/v1/project-router.ts b/backend/src/server/routes/v1/project-router.ts index dc32702ff5..3ffedf98d7 100644 --- a/backend/src/server/routes/v1/project-router.ts +++ b/backend/src/server/routes/v1/project-router.ts @@ -7,6 +7,7 @@ import { UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas"; +import { PROJECTS } from "@app/lib/api-docs"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -125,7 +126,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { method: "GET", schema: { params: z.object({ - workspaceId: z.string().trim() + workspaceId: z.string().trim().describe(PROJECTS.GET.workspaceId) }), response: { 200: z.object({ @@ -177,7 +178,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { method: "DELETE", schema: { params: z.object({ - workspaceId: z.string().trim() + workspaceId: z.string().trim().describe(PROJECTS.DELETE.workspaceId) }), response: { 200: z.object({ @@ -235,11 +236,16 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { method: "PATCH", schema: { params: z.object({ - workspaceId: z.string().trim() + workspaceId: z.string().trim().describe(PROJECTS.UPDATE.workspaceId) }), body: z.object({ - name: z.string().trim().max(64, { message: "Name must be 64 or fewer characters" }).optional(), - autoCapitalization: z.boolean().optional() + name: z + .string() + .trim() + .max(64, { message: "Name must be 64 or fewer characters" }) + .optional() + .describe(PROJECTS.UPDATE.name), + autoCapitalization: z.boolean().optional().describe(PROJECTS.UPDATE.autoCapitalization) }), response: { 200: z.object({ diff --git a/backend/src/server/routes/v1/secret-folder-router.ts b/backend/src/server/routes/v1/secret-folder-router.ts index af1bf72126..dee075943e 100644 --- a/backend/src/server/routes/v1/secret-folder-router.ts +++ b/backend/src/server/routes/v1/secret-folder-router.ts @@ -2,6 +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 { removeTrailingSlash } from "@app/lib/fn"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -19,12 +20,12 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => } ], body: z.object({ - workspaceId: z.string().trim(), - environment: z.string().trim(), - name: z.string().trim(), - path: z.string().trim().default("/").transform(removeTrailingSlash), + workspaceId: z.string().trim().describe(FOLDERS.CREATE.workspaceId), + environment: z.string().trim().describe(FOLDERS.CREATE.environment), + name: z.string().trim().describe(FOLDERS.CREATE.name), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.CREATE.path), // backward compatiability with cli - directory: z.string().trim().default("/").transform(removeTrailingSlash) + directory: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.CREATE.directory) }), response: { 200: z.object({ @@ -73,15 +74,15 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => ], params: z.object({ // old way this was name - folderId: z.string() + folderId: z.string().describe(FOLDERS.UPDATE.folderId) }), body: z.object({ - workspaceId: z.string().trim(), - environment: z.string().trim(), - name: z.string().trim(), - path: z.string().trim().default("/").transform(removeTrailingSlash), + workspaceId: z.string().trim().describe(FOLDERS.UPDATE.workspaceId), + environment: z.string().trim().describe(FOLDERS.UPDATE.environment), + name: z.string().trim().describe(FOLDERS.UPDATE.name), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.UPDATE.path), // backward compatiability with cli - directory: z.string().trim().default("/").transform(removeTrailingSlash) + directory: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.UPDATE.directory) }), response: { 200: z.object({ @@ -119,6 +120,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => } }); + // TODO(daniel): Expose this route in api reference and write docs for it. server.route({ url: "/:folderIdOrName", method: "DELETE", @@ -131,14 +133,14 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => } ], params: z.object({ - folderIdOrName: z.string() + folderIdOrName: z.string().describe(FOLDERS.DELETE.folderIdOrName) }), body: z.object({ - workspaceId: z.string().trim(), - environment: z.string().trim(), - path: z.string().trim().default("/").transform(removeTrailingSlash), + workspaceId: z.string().trim().describe(FOLDERS.DELETE.workspaceId), + environment: z.string().trim().describe(FOLDERS.DELETE.environment), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.DELETE.path), // keep this here as cli need directory - directory: z.string().trim().default("/").transform(removeTrailingSlash) + directory: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.DELETE.directory) }), response: { 200: z.object({ @@ -187,11 +189,11 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) => } ], querystring: z.object({ - workspaceId: z.string().trim(), - environment: z.string().trim(), - path: z.string().trim().default("/").transform(removeTrailingSlash), + workspaceId: z.string().trim().describe(FOLDERS.LIST.workspaceId), + environment: z.string().trim().describe(FOLDERS.LIST.environment), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.LIST.path), // backward compatiability with cli - directory: z.string().trim().default("/").transform(removeTrailingSlash) + directory: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.LIST.directory) }), response: { 200: z.object({ diff --git a/backend/src/server/routes/v1/secret-import-router.ts b/backend/src/server/routes/v1/secret-import-router.ts index 2ec2d5ce2e..823e7dbee0 100644 --- a/backend/src/server/routes/v1/secret-import-router.ts +++ b/backend/src/server/routes/v1/secret-import-router.ts @@ -2,6 +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 { removeTrailingSlash } from "@app/lib/fn"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -19,12 +20,12 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => } ], body: z.object({ - workspaceId: z.string().trim(), - environment: z.string().trim(), - path: z.string().trim().default("/").transform(removeTrailingSlash), + workspaceId: z.string().trim().describe(SECRET_IMPORTS.CREATE.workspaceId), + environment: z.string().trim().describe(SECRET_IMPORTS.CREATE.environment), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.CREATE.path), import: z.object({ - environment: z.string().trim(), - path: z.string().trim().transform(removeTrailingSlash) + environment: z.string().trim().describe(SECRET_IMPORTS.CREATE.import.environment), + path: z.string().trim().transform(removeTrailingSlash).describe(SECRET_IMPORTS.CREATE.import.path) }) }), response: { @@ -80,20 +81,21 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => } ], params: z.object({ - secretImportId: z.string().trim() + secretImportId: z.string().trim().describe(SECRET_IMPORTS.UPDATE.secretImportId) }), body: z.object({ - workspaceId: z.string().trim(), - environment: z.string().trim(), - path: z.string().trim().default("/").transform(removeTrailingSlash), + workspaceId: z.string().trim().describe(SECRET_IMPORTS.UPDATE.workspaceId), + environment: z.string().trim().describe(SECRET_IMPORTS.UPDATE.environment), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.UPDATE.path), import: z.object({ - environment: z.string().trim().optional(), + environment: z.string().trim().optional().describe(SECRET_IMPORTS.UPDATE.import.environment), path: z .string() .trim() .optional() - .transform((val) => (val ? removeTrailingSlash(val) : val)), - position: z.number().optional() + .transform((val) => (val ? removeTrailingSlash(val) : val)) + .describe(SECRET_IMPORTS.UPDATE.import.path), + position: z.number().optional().describe(SECRET_IMPORTS.UPDATE.import.position) }) }), response: { @@ -150,12 +152,12 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => } ], params: z.object({ - secretImportId: z.string().trim() + secretImportId: z.string().trim().describe(SECRET_IMPORTS.DELETE.secretImportId) }), body: z.object({ - workspaceId: z.string().trim(), - environment: z.string().trim(), - path: z.string().trim().default("/").transform(removeTrailingSlash) + workspaceId: z.string().trim().describe(SECRET_IMPORTS.DELETE.workspaceId), + environment: z.string().trim().describe(SECRET_IMPORTS.DELETE.environment), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.DELETE.path) }), response: { 200: z.object({ @@ -210,9 +212,9 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) => } ], querystring: z.object({ - workspaceId: z.string().trim(), - environment: z.string().trim(), - path: z.string().trim().default("/").transform(removeTrailingSlash) + workspaceId: z.string().trim().describe(SECRET_IMPORTS.LIST.workspaceId), + environment: z.string().trim().describe(SECRET_IMPORTS.LIST.environment), + path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.LIST.path) }), response: { 200: z.object({ diff --git a/backend/src/server/routes/v2/identity-org-router.ts b/backend/src/server/routes/v2/identity-org-router.ts index 1832e89621..97477b0332 100644 --- a/backend/src/server/routes/v2/identity-org-router.ts +++ b/backend/src/server/routes/v2/identity-org-router.ts @@ -1,6 +1,7 @@ import { z } from "zod"; import { IdentitiesSchema, IdentityOrgMembershipsSchema, OrgRolesSchema } from "@app/db/schemas"; +import { ORGANIZATIONS } from "@app/lib/api-docs"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -18,7 +19,7 @@ export const registerIdentityOrgRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - orgId: z.string().trim() + orgId: z.string().trim().describe(ORGANIZATIONS.LIST_IDENTITY_MEMBERSHIPS.orgId) }), response: { 200: z.object({ diff --git a/backend/src/server/routes/v2/identity-project-router.ts b/backend/src/server/routes/v2/identity-project-router.ts index 09e5868394..67dccb5e3c 100644 --- a/backend/src/server/routes/v2/identity-project-router.ts +++ b/backend/src/server/routes/v2/identity-project-router.ts @@ -7,6 +7,7 @@ import { ProjectMembershipRole, ProjectUserMembershipRolesSchema } from "@app/db/schemas"; +import { PROJECTS } from "@app/lib/api-docs"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; import { ProjectUserMembershipTemporaryMode } from "@app/services/project-membership/project-membership-types"; @@ -55,8 +56,8 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider) } ], params: z.object({ - projectId: z.string().trim(), - identityId: z.string().trim() + projectId: z.string().trim().describe(PROJECTS.UPDATE_IDENTITY_MEMBERSHIP.projectId), + identityId: z.string().trim().describe(PROJECTS.UPDATE_IDENTITY_MEMBERSHIP.identityId) }), body: z.object({ roles: z @@ -76,6 +77,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider) ]) ) .min(1) + .describe(PROJECTS.UPDATE_IDENTITY_MEMBERSHIP.roles) }), response: { 200: z.object({ @@ -108,8 +110,8 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider) } ], params: z.object({ - projectId: z.string().trim(), - identityId: z.string().trim() + projectId: z.string().trim().describe(PROJECTS.DELETE_IDENTITY_MEMBERSHIP.projectId), + identityId: z.string().trim().describe(PROJECTS.DELETE_IDENTITY_MEMBERSHIP.identityId) }), response: { 200: z.object({ @@ -141,7 +143,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider) } ], params: z.object({ - projectId: z.string().trim() + projectId: z.string().trim().describe(PROJECTS.LIST_IDENTITY_MEMBERSHIPS.projectId) }), response: { 200: z.object({ diff --git a/backend/src/server/routes/v2/organization-router.ts b/backend/src/server/routes/v2/organization-router.ts index ba5ca3c21c..7d5ba3da7a 100644 --- a/backend/src/server/routes/v2/organization-router.ts +++ b/backend/src/server/routes/v2/organization-router.ts @@ -1,6 +1,7 @@ import { z } from "zod"; import { OrganizationsSchema, OrgMembershipsSchema, UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas"; +import { ORGANIZATIONS } from "@app/lib/api-docs"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { ActorType, AuthMode } from "@app/services/auth/auth-type"; @@ -17,7 +18,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - organizationId: z.string().trim() + organizationId: z.string().trim().describe(ORGANIZATIONS.LIST_USER_MEMBERSHIPS.organizationId) }), response: { 200: z.object({ @@ -62,7 +63,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - organizationId: z.string().trim() + organizationId: z.string().trim().describe(ORGANIZATIONS.GET_PROJECTS.organizationId) }), response: { 200: z.object({ @@ -106,9 +107,12 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { apiKeyAuth: [] } ], - params: z.object({ organizationId: z.string().trim(), membershipId: z.string().trim() }), + params: z.object({ + organizationId: z.string().trim().describe(ORGANIZATIONS.UPDATE_USER_MEMBERSHIP.organizationId), + membershipId: z.string().trim().describe(ORGANIZATIONS.UPDATE_USER_MEMBERSHIP.membershipId) + }), body: z.object({ - role: z.string().trim() + role: z.string().trim().describe(ORGANIZATIONS.UPDATE_USER_MEMBERSHIP.role) }), response: { 200: z.object({ @@ -142,7 +146,10 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { apiKeyAuth: [] } ], - params: z.object({ organizationId: z.string().trim(), membershipId: z.string().trim() }), + params: z.object({ + organizationId: z.string().trim().describe(ORGANIZATIONS.DELETE_USER_MEMBERSHIP.organizationId), + membershipId: z.string().trim().describe(ORGANIZATIONS.DELETE_USER_MEMBERSHIP.membershipId) + }), response: { 200: z.object({ membership: OrgMembershipsSchema diff --git a/backend/src/server/routes/v2/project-membership-router.ts b/backend/src/server/routes/v2/project-membership-router.ts index f63770346b..6f81f83920 100644 --- a/backend/src/server/routes/v2/project-membership-router.ts +++ b/backend/src/server/routes/v2/project-membership-router.ts @@ -2,6 +2,7 @@ import { z } from "zod"; import { ProjectMembershipsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { PROJECTS } from "@app/lib/api-docs"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; @@ -11,11 +12,11 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider url: "/:projectId/memberships", schema: { params: z.object({ - projectId: z.string().describe("The ID of the project.") + projectId: z.string().describe(PROJECTS.INVITE_MEMBER.projectId) }), body: z.object({ - emails: z.string().email().array().default([]).describe("Emails of the users to add to the project."), - usernames: z.string().array().default([]).describe("Usernames of the users to add to the project.") + emails: z.string().email().array().default([]).describe(PROJECTS.INVITE_MEMBER.emails), + usernames: z.string().array().default([]).describe(PROJECTS.INVITE_MEMBER.usernames) }), response: { 200: z.object({ @@ -55,12 +56,12 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider url: "/:projectId/memberships", schema: { params: z.object({ - projectId: z.string().describe("The ID of the project.") + projectId: z.string().describe(PROJECTS.REMOVE_MEMBER.projectId) }), body: z.object({ - emails: z.string().email().array().default([]).describe("Emails of the users to remove from the project."), - usernames: z.string().array().default([]).describe("Usernames of the users to remove from the project.") + emails: z.string().email().array().default([]).describe(PROJECTS.REMOVE_MEMBER.emails), + usernames: z.string().array().default([]).describe(PROJECTS.REMOVE_MEMBER.usernames) }), response: { 200: z.object({ diff --git a/backend/src/server/routes/v2/project-router.ts b/backend/src/server/routes/v2/project-router.ts index fe1254b2b3..208edba7b9 100644 --- a/backend/src/server/routes/v2/project-router.ts +++ b/backend/src/server/routes/v2/project-router.ts @@ -3,6 +3,7 @@ import { z } from "zod"; import { ProjectKeysSchema, ProjectsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { PROJECTS } from "@app/lib/api-docs"; import { authRateLimit } from "@app/server/config/rateLimiter"; import { getTelemetryDistinctId } from "@app/server/lib/telemetry"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -29,7 +30,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - workspaceId: z.string().trim() + workspaceId: z.string().trim().describe(PROJECTS.GET_KEY.workspaceId) }), response: { 200: ProjectKeysSchema.merge( @@ -127,7 +128,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { }, schema: { body: z.object({ - projectName: z.string().trim(), + projectName: z.string().trim().describe(PROJECTS.CREATE.projectName), slug: z .string() .min(5) @@ -135,8 +136,9 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { .refine((v) => slugify(v) === v, { message: "Slug must be a valid slug" }) - .optional(), - organizationId: z.string().trim() + .optional() + .describe(PROJECTS.CREATE.slug), + organizationId: z.string().trim().describe(PROJECTS.CREATE.organizationId) }), response: { 200: z.object({ diff --git a/backend/src/server/routes/v3/secret-router.ts b/backend/src/server/routes/v3/secret-router.ts index 6b3dd60413..65219d0ab9 100644 --- a/backend/src/server/routes/v3/secret-router.ts +++ b/backend/src/server/routes/v3/secret-router.ts @@ -10,6 +10,7 @@ import { } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { CommitType } from "@app/ee/services/secret-approval-request/secret-approval-request-types"; +import { RAW_SECRETS } from "@app/lib/api-docs"; import { BadRequestError } from "@app/lib/errors"; import { removeTrailingSlash } from "@app/lib/fn"; import { getTelemetryDistinctId } from "@app/server/lib/telemetry"; @@ -33,13 +34,14 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { } ], querystring: z.object({ - workspaceId: z.string().trim().optional(), - environment: z.string().trim().optional(), - secretPath: z.string().trim().default("/").transform(removeTrailingSlash), + workspaceId: z.string().trim().optional().describe(RAW_SECRETS.LIST.workspaceId), + environment: z.string().trim().optional().describe(RAW_SECRETS.LIST.environment), + secretPath: z.string().trim().default("/").transform(removeTrailingSlash).describe(RAW_SECRETS.LIST.secretPath), include_imports: z .enum(["true", "false"]) .default("false") .transform((value) => value === "true") + .describe(RAW_SECRETS.LIST.includeImports) }), response: { 200: z.object({ @@ -123,18 +125,19 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - secretName: z.string().trim() + secretName: z.string().trim().describe(RAW_SECRETS.GET.secretName) }), querystring: z.object({ - workspaceId: z.string().trim().optional(), - environment: z.string().trim().optional(), - secretPath: z.string().trim().default("/").transform(removeTrailingSlash), - version: z.coerce.number().optional(), - type: z.nativeEnum(SecretType).default(SecretType.Shared), + workspaceId: z.string().trim().optional().describe(RAW_SECRETS.GET.workspaceId), + environment: z.string().trim().optional().describe(RAW_SECRETS.GET.environment), + secretPath: z.string().trim().default("/").transform(removeTrailingSlash).describe(RAW_SECRETS.GET.secretPath), + version: z.coerce.number().optional().describe(RAW_SECRETS.GET.version), + type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(RAW_SECRETS.GET.type), include_imports: z .enum(["true", "false"]) .default("false") .transform((value) => value === "true") + .describe(RAW_SECRETS.GET.includeImports) }), response: { 200: z.object({ @@ -213,16 +216,24 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - secretName: z.string().trim() + secretName: z.string().trim().describe(RAW_SECRETS.CREATE.secretName) }), body: z.object({ - workspaceId: z.string().trim(), - environment: z.string().trim(), - secretPath: z.string().trim().default("/").transform(removeTrailingSlash), - secretValue: z.string().transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())), - secretComment: z.string().trim().optional().default(""), - skipMultilineEncoding: z.boolean().optional(), - type: z.nativeEnum(SecretType).default(SecretType.Shared) + workspaceId: z.string().trim().describe(RAW_SECRETS.CREATE.workspaceId), + environment: z.string().trim().describe(RAW_SECRETS.CREATE.environment), + secretPath: z + .string() + .trim() + .default("/") + .transform(removeTrailingSlash) + .describe(RAW_SECRETS.CREATE.secretPath), + secretValue: z + .string() + .transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())) + .describe(RAW_SECRETS.CREATE.secretValue), + secretComment: z.string().trim().optional().default("").describe(RAW_SECRETS.CREATE.secretComment), + skipMultilineEncoding: z.boolean().optional().describe(RAW_SECRETS.CREATE.skipMultilineEncoding), + type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(RAW_SECRETS.CREATE.type) }), response: { 200: z.object({ @@ -290,15 +301,23 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - secretName: z.string().trim() + secretName: z.string().trim().describe(RAW_SECRETS.UPDATE.secretName) }), body: z.object({ - workspaceId: z.string().trim(), - environment: z.string().trim(), - secretValue: z.string().transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())), - secretPath: z.string().trim().default("/").transform(removeTrailingSlash), - skipMultilineEncoding: z.boolean().optional(), - type: z.nativeEnum(SecretType).default(SecretType.Shared) + workspaceId: z.string().trim().describe(RAW_SECRETS.UPDATE.workspaceId), + environment: z.string().trim().describe(RAW_SECRETS.UPDATE.environment), + secretValue: z + .string() + .transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())) + .describe(RAW_SECRETS.UPDATE.secretValue), + secretPath: z + .string() + .trim() + .default("/") + .transform(removeTrailingSlash) + .describe(RAW_SECRETS.UPDATE.secretPath), + skipMultilineEncoding: z.boolean().optional().describe(RAW_SECRETS.UPDATE.skipMultilineEncoding), + type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(RAW_SECRETS.UPDATE.type) }), response: { 200: z.object({ @@ -364,13 +383,18 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { } ], params: z.object({ - secretName: z.string().trim() + secretName: z.string().trim().describe(RAW_SECRETS.DELETE.secretName) }), body: z.object({ - workspaceId: z.string().trim(), - environment: z.string().trim(), - secretPath: z.string().trim().default("/").transform(removeTrailingSlash), - type: z.nativeEnum(SecretType).default(SecretType.Shared) + workspaceId: z.string().trim().describe(RAW_SECRETS.DELETE.workspaceId), + environment: z.string().trim().describe(RAW_SECRETS.DELETE.environment), + secretPath: z + .string() + .trim() + .default("/") + .transform(removeTrailingSlash) + .describe(RAW_SECRETS.DELETE.secretPath), + type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(RAW_SECRETS.DELETE.type) }), response: { 200: z.object({ From 5194be14fddfed41b8587dadf916f7929e887fa2 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:40:53 +0100 Subject: [PATCH 04/11] Update mint.json --- docs/mint.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mint.json b/docs/mint.json index 74b56f3b02..3e8451ecea 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -1,6 +1,6 @@ { "name": "Infisical", - "openapi": "https://app.infisical.com/api/docs/json", + "openapi": "http://localhost:8080/api/docs/json", "logo": { "dark": "/logo/dark.svg", "light": "/logo/light.svg", From 288577b4557072a8c672fe7dd53784d77345b5eb Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:41:32 +0100 Subject: [PATCH 05/11] Fix: OpenAPI specification URL --- docs/mint.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mint.json b/docs/mint.json index 3e8451ecea..74b56f3b02 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -1,6 +1,6 @@ { "name": "Infisical", - "openapi": "http://localhost:8080/api/docs/json", + "openapi": "https://app.infisical.com/api/docs/json", "logo": { "dark": "/logo/dark.svg", "light": "/logo/light.svg", From 36266b30d5cb8d308ed02a8b0e372bf097f84bcb Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:09:21 +0100 Subject: [PATCH 06/11] Fix: Shorter sidebar title --- docs/sdks/languages/csharp.mdx | 3 ++- docs/sdks/languages/java.mdx | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/sdks/languages/csharp.mdx b/docs/sdks/languages/csharp.mdx index ecfd67c27b..b3a1d20868 100644 --- a/docs/sdks/languages/csharp.mdx +++ b/docs/sdks/languages/csharp.mdx @@ -1,6 +1,7 @@ --- title: "Infisical .NET SDK" -icon: "C#" +sidebarTitle: ".NET" +icon: "bars" --- If you're working with C#, the official [Infisical C# SDK](https://github.com/Infisical/sdk/tree/main/languages/csharp) package is the easiest way to fetch and work with secrets for your application. diff --git a/docs/sdks/languages/java.mdx b/docs/sdks/languages/java.mdx index 40d577926c..5b8797b5d3 100644 --- a/docs/sdks/languages/java.mdx +++ b/docs/sdks/languages/java.mdx @@ -1,5 +1,6 @@ --- title: "Infisical Java SDK" +sidebarTitle: "Java" icon: "java" --- From 0c88a5466c46df6d465ab4bd3534970f63695f07 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:09:37 +0100 Subject: [PATCH 07/11] Feat: Documentation improvements --- docs/mint.json | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/docs/mint.json b/docs/mint.json index 74b56f3b02..4040b9eb1c 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -39,32 +39,29 @@ "name": "Start for Free", "url": "https://app.infisical.com/signup" }, - "anchors": [ - { - "name": "Internals", - "icon": "sitemap", - "url": "internals" - }, - { - "name": "SDKs", - "icon": "puzzle-piece", - "url": "sdks" - }, - { - "name": "API Reference", - "icon": "cloud", - "url": "api-reference" - }, + "tabs": [ { "name": "Changelog", - "icon": "timer", "url": "changelog" }, + { + "name": "API Reference", + "url": "api-reference" + }, + { + "name": "Libraries", + "url": "sdks" + }, { "name": "Contributing", - "icon": "code", "url": "contributing" }, + { + "name": "Internals", + "url": "internals" + } + ], + "anchors": [ { "name": "Blog", "icon": "newspaper", @@ -356,7 +353,18 @@ }, { "group": "Overview", - "pages": ["sdks/overview"] + "pages": [ + "sdks/overview", + { + "group": "Libraries", + "pages": [ + "sdks/languages/node", + "sdks/languages/python", + "sdks/languages/java", + "sdks/languages/csharp" + ] + } + ] }, { "group": "Overview", From 70bd64d54b2d016d1c3f1b1922a50ec02758c1e1 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:09:45 +0100 Subject: [PATCH 08/11] Fix: Shorter sidebar titles --- docs/sdks/languages/node.mdx | 1 + docs/sdks/languages/python.mdx | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/sdks/languages/node.mdx b/docs/sdks/languages/node.mdx index 7712caaf1b..4816392ed6 100644 --- a/docs/sdks/languages/node.mdx +++ b/docs/sdks/languages/node.mdx @@ -1,5 +1,6 @@ --- title: "Infisical Node.js SDK" +sidebarTitle: "Node.js" icon: "node" --- diff --git a/docs/sdks/languages/python.mdx b/docs/sdks/languages/python.mdx index da92b1a6ed..0ce221757a 100644 --- a/docs/sdks/languages/python.mdx +++ b/docs/sdks/languages/python.mdx @@ -1,5 +1,6 @@ --- title: "Infisical Python SDK" +sidebarTitle: "Python" icon: "python" --- From 11dfeda50167b9c45eedf70143ab3f722b01851c Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:13:18 +0100 Subject: [PATCH 09/11] Fix: No nested groups --- docs/mint.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/mint.json b/docs/mint.json index 4040b9eb1c..0207dda242 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -354,16 +354,16 @@ { "group": "Overview", "pages": [ - "sdks/overview", - { - "group": "Libraries", - "pages": [ - "sdks/languages/node", - "sdks/languages/python", - "sdks/languages/java", - "sdks/languages/csharp" - ] - } + "sdks/overview" + ] + }, + { + "group": "Libraries", + "pages": [ + "sdks/languages/node", + "sdks/languages/python", + "sdks/languages/java", + "sdks/languages/csharp" ] }, { From 97eff2b480d12bafdf70839c952ce4014a1b7321 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Thu, 14 Mar 2024 18:04:27 +0100 Subject: [PATCH 10/11] Fix: Moved categories and renamed Libs -> SDKs --- docs/mint.json | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/docs/mint.json b/docs/mint.json index 0207dda242..fd4964e561 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -49,19 +49,22 @@ "url": "api-reference" }, { - "name": "Libraries", + "name": "SDKs", "url": "sdks" }, { "name": "Contributing", "url": "contributing" - }, - { - "name": "Internals", - "url": "internals" } ], "anchors": [ + + { + "name": "Contributing", + "icon": "code", + "url": "contributing" + }, + { "name": "Blog", "icon": "newspaper", @@ -76,6 +79,11 @@ "name": "GitHub", "icon": "github", "url": "https://github.com/Infisical/infisical" + }, + { + "name": "Internals", + "icon": "sitemap", + "url": "internals" } ], "navigation": [ From 519b92d59257bac9070f935c66751da9d7e5ed3d Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Thu, 14 Mar 2024 19:05:34 +0100 Subject: [PATCH 11/11] Update mint.json --- docs/mint.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/mint.json b/docs/mint.json index fd4964e561..f221eceaaa 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -366,7 +366,7 @@ ] }, { - "group": "Libraries", + "group": "SDK's", "pages": [ "sdks/languages/node", "sdks/languages/python",