Compare commits

..

20 Commits

Author SHA1 Message Date
519b92d592 Update mint.json 2024-03-14 19:05:34 +01:00
97eff2b480 Fix: Moved categories and renamed Libs -> SDKs 2024-03-14 18:04:27 +01:00
11dfeda501 Fix: No nested groups 2024-03-14 17:13:18 +01:00
70bd64d54b Fix: Shorter sidebar titles 2024-03-14 17:09:45 +01:00
0c88a5466c Feat: Documentation improvements 2024-03-14 17:09:37 +01:00
36266b30d5 Fix: Shorter sidebar title 2024-03-14 17:09:21 +01:00
288577b455 Fix: OpenAPI specification URL 2024-03-14 15:41:32 +01:00
5194be14fd Update mint.json 2024-03-14 15:40:53 +01:00
bab8f95fde Feat: Added descriptions to all public API endpoints 2024-03-14 15:40:38 +01:00
b4f372f883 Fix: Delete folder docs page not rendering 2024-03-14 15:40:08 +01:00
b13365ecf5 Feat: Written API explanations 2024-03-14 15:39:29 +01:00
70618420d7 Merge pull request #1565 from Infisical/daniel/deprecate-service-tokens-and-api-keys
Feat: Deprecate API keys
2024-03-13 17:58:05 +01:00
7feb7ef9c6 Fix: Change title 2024-03-13 17:52:24 +01:00
ab1b9fb164 Feat: Deprecate API keys 2024-03-13 17:46:48 +01:00
8c028889a6 Chore: Remove unused frontend V2 API key code 2024-03-13 17:45:19 +01:00
7dc366baf0 Merge pull request #1562 from rhythmbhiwani/fix-typo
Fix typo on Copy button tooltip
2024-03-13 16:28:42 +05:30
2124d2669f Merge pull request #1564 from myapos/bugfix_1563_remove_member
fix issue on removing member from project
2024-03-13 16:24:18 +05:30
af83fbea14 fix issue on removing member from project 2024-03-13 12:32:11 +02:00
9657b64ab2 Fix typo on Copy button tooltip 2024-03-13 15:54:42 +05:30
90b55a94e1 Merge pull request #1561 from Infisical/pg-new-connection
add individual pg connection properties
2024-03-13 00:43:45 -04:00
33 changed files with 637 additions and 618 deletions

View File

@ -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({

View File

@ -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({

View File

@ -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;

View File

@ -0,0 +1 @@
export * from "./constants";

View File

@ -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({

View File

@ -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({

View File

@ -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({

View File

@ -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({

View File

@ -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({

View File

@ -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({

View File

@ -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({

View File

@ -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({

View File

@ -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({

View File

@ -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({

View File

@ -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

View File

@ -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({

View File

@ -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({

View File

@ -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({

View File

@ -1,4 +1,4 @@
---
title: "Delete"
openapi: "DELETE /api/v1/folders/{folderId}"
openapi: "DELETE /api/v1/folders/{folderIdOrName}"
---

View File

@ -39,32 +39,32 @@
"name": "Start for Free",
"url": "https://app.infisical.com/signup"
},
"anchors": [
"tabs": [
{
"name": "Internals",
"icon": "sitemap",
"url": "internals"
},
{
"name": "SDKs",
"icon": "puzzle-piece",
"url": "sdks"
"name": "Changelog",
"url": "changelog"
},
{
"name": "API Reference",
"icon": "cloud",
"url": "api-reference"
},
{
"name": "Changelog",
"icon": "timer",
"url": "changelog"
"name": "SDKs",
"url": "sdks"
},
{
"name": "Contributing",
"url": "contributing"
}
],
"anchors": [
{
"name": "Contributing",
"icon": "code",
"url": "contributing"
},
{
"name": "Blog",
"icon": "newspaper",
@ -79,6 +79,11 @@
"name": "GitHub",
"icon": "github",
"url": "https://github.com/Infisical/infisical"
},
{
"name": "Internals",
"icon": "sitemap",
"url": "internals"
}
],
"navigation": [
@ -356,7 +361,18 @@
},
{
"group": "Overview",
"pages": ["sdks/overview"]
"pages": [
"sdks/overview"
]
},
{
"group": "SDK's",
"pages": [
"sdks/languages/node",
"sdks/languages/python",
"sdks/languages/java",
"sdks/languages/csharp"
]
},
{
"group": "Overview",

View File

@ -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.

View File

@ -1,5 +1,6 @@
---
title: "Infisical Java SDK"
sidebarTitle: "Java"
icon: "java"
---

View File

@ -1,5 +1,6 @@
---
title: "Infisical Node.js SDK"
sidebarTitle: "Node.js"
icon: "node"
---

View File

@ -1,5 +1,6 @@
---
title: "Infisical Python SDK"
sidebarTitle: "Python"
icon: "python"
---

View File

@ -261,7 +261,9 @@ export const MemberListTab = () => {
ariaLabel="update"
className="ml-4"
isDisabled={userId === u?.id || !isAllowed}
onClick={() => handlePopUpOpen("removeMember", { email: u.email })}
onClick={() =>
handlePopUpOpen("removeMember", { username: u.username })
}
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>

View File

@ -188,7 +188,7 @@ function SecretRenameRow({ environments, getSecretByKey, secretKey, secretPath }
animate={{ x: 0, opacity: 1 }}
exit={{ x: 10, opacity: 0 }}
>
<Tooltip content="Copy secret">
<Tooltip content="Copy secret name">
<IconButton
ariaLabel="copy-value"
variant="plain"

View File

@ -2,38 +2,36 @@ import { useTranslation } from "react-i18next";
import { faPlus } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Button } from "@app/components/v2";
import { Button, Tooltip } from "@app/components/v2";
import { usePopUp } from "@app/hooks/usePopUp";
import { AddAPIKeyModal } from "./AddAPIKeyModal";
import { APIKeyTable } from "./APIKeyTable";
export const APIKeySection = () => {
const { t } = useTranslation();
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp([
"addAPIKey"
] as const);
const { t } = useTranslation();
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["addAPIKey"] as const);
return (
<div className="mb-6 p-4 bg-mineshaft-900 rounded-lg border border-mineshaft-600">
<div className="flex justify-between mb-8">
<p className="text-xl font-semibold text-mineshaft-100">
{t("settings.personal.api-keys.title")}
</p>
<Button
colorSchema="secondary"
type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => handlePopUpOpen("addAPIKey")}
>
Add API Key
</Button>
</div>
<APIKeyTable />
<AddAPIKeyModal
popUp={popUp}
handlePopUpToggle={handlePopUpToggle}
/>
</div>
);
}
return (
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-8 flex justify-between">
<p className="text-xl font-semibold text-mineshaft-100">
{t("settings.personal.api-keys.title")}
</p>
<Tooltip content="API Keys are deprecated and will be removed in the future.">
<Button
isDisabled
colorSchema="secondary"
type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => handlePopUpOpen("addAPIKey")}
>
Add API Key
</Button>
</Tooltip>
</div>
<APIKeyTable />
<AddAPIKeyModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
</div>
);
};

View File

@ -1,199 +0,0 @@
import { useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import {
Button,
FormControl,
IconButton,
Input,
Modal,
ModalContent} from "@app/components/v2";
import { useToggle } from "@app/hooks";
import {
useCreateAPIKeyV2,
useUpdateAPIKeyV2
} from "@app/hooks/api";
import { UsePopUpState } from "@app/hooks/usePopUp";
const schema = yup.object({
name: yup.string().required("API Key V2 name is required")
}).required();
export type FormData = yup.InferType<typeof schema>;
type Props = {
popUp: UsePopUpState<["apiKeyV2"]>;
handlePopUpToggle: (popUpName: keyof UsePopUpState<["apiKeyV2"]>, state?: boolean) => void;
};
export const APIKeyV2Modal = ({
popUp,
handlePopUpToggle
}: Props) => {
const [newAPIKey, setNewAPIKey] = useState("");
const [isAPIKeyCopied, setIsAPIKeyCopied] = useToggle(false);
const { createNotification } = useNotificationContext();
const { mutateAsync: createMutateAsync } = useCreateAPIKeyV2();
const { mutateAsync: updateMutateAsync } = useUpdateAPIKeyV2();
const {
control,
handleSubmit,
reset,
formState: { isSubmitting }
} = useForm<FormData>({
resolver: yupResolver(schema),
defaultValues: {
name: ""
}
});
useEffect(() => {
let timer: NodeJS.Timeout;
if (isAPIKeyCopied) {
timer = setTimeout(() => setIsAPIKeyCopied.off(), 2000);
}
return () => clearTimeout(timer);
}, [setIsAPIKeyCopied]);
useEffect(() => {
const apiKeyData = popUp?.apiKeyV2?.data as {
apiKeyDataId: string;
name: string;
};
if (apiKeyData) {
reset({
name: apiKeyData.name
});
} else {
reset({
name: ""
});
}
}, [popUp?.apiKeyV2?.data]);
const copyTokenToClipboard = () => {
navigator.clipboard.writeText(newAPIKey);
setIsAPIKeyCopied.on();
};
const onFormSubmit = async ({
name
}: FormData) => {
try {
const apiKeyData = popUp?.apiKeyV2?.data as {
apiKeyDataId: string;
name: string;
};
if (apiKeyData) {
// update
await updateMutateAsync({
apiKeyDataId: apiKeyData.apiKeyDataId,
name
});
handlePopUpToggle("apiKeyV2", false);
} else {
// create
const { apiKey } = await createMutateAsync({
name
});
setNewAPIKey(apiKey);
}
createNotification({
text: `Successfully ${popUp?.apiKeyV2?.data ? "updated" : "created"} API Key`,
type: "success"
});
reset();
} catch (err) {
console.error(err);
createNotification({
text: `Failed to ${popUp?.apiKeyV2?.data ? "updated" : "created"} API Key`,
type: "error"
});
}
}
const hasAPIKey = Boolean(newAPIKey);
return (
<Modal
isOpen={popUp?.apiKeyV2?.isOpen}
onOpenChange={(isOpen) => {
handlePopUpToggle("apiKeyV2", isOpen);
reset();
setNewAPIKey("");
}}
>
<ModalContent title={`${popUp?.apiKeyV2?.data ? "Update" : "Create"} API Key V2`}>
{!hasAPIKey ? (
<form onSubmit={handleSubmit(onFormSubmit)}>
<Controller
control={control}
defaultValue=""
name="name"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Name"
isError={Boolean(error)}
errorText={error?.message}
>
<Input
{...field}
placeholder="My API Key"
/>
</FormControl>
)}
/>
<div className="mt-8 flex items-center">
<Button
className="mr-4"
size="sm"
type="submit"
isLoading={isSubmitting}
isDisabled={isSubmitting}
>
{popUp?.apiKeyV2?.data ? "Update" : "Create"}
</Button>
<Button colorSchema="secondary" variant="plain">
Cancel
</Button>
</div>
</form>
) : (
<div className="mt-2 mb-3 mr-2 flex items-center justify-end rounded-md bg-white/[0.07] p-2 text-base text-gray-400">
<p className="mr-4 break-all">{newAPIKey}</p>
<IconButton
ariaLabel="copy icon"
colorSchema="secondary"
className="group relative"
onClick={copyTokenToClipboard}
>
<FontAwesomeIcon icon={isAPIKeyCopied ? faCheck : faCopy} />
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-bunker-800 py-2 pl-3 text-center text-sm text-gray-400 group-hover:flex group-hover:animate-fadeIn">
Click to copy
</span>
</IconButton>
</div>
)}
</ModalContent>
</Modal>
);
}

View File

@ -1,81 +0,0 @@
import { faPlus } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import {
Button,
DeleteActionModal
} from "@app/components/v2";
import { useDeleteAPIKeyV2 } from "@app/hooks/api";
import { usePopUp } from "@app/hooks/usePopUp";
import { APIKeyV2Modal } from "./APIKeyV2Modal";
import { APIKeyV2Table } from "./APIKeyV2Table";
export const APIKeyV2Section = () => {
const { createNotification } = useNotificationContext();
const { mutateAsync: deleteMutateAsync } = useDeleteAPIKeyV2();
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
"apiKeyV2",
"deleteAPIKeyV2"
] as const);
const onDeleteAPIKeyDataSubmit = async (apiKeyDataId: string) => {
try {
await deleteMutateAsync({
apiKeyDataId
});
createNotification({
text: "Successfully deleted API Key V2",
type: "success"
});
handlePopUpClose("deleteAPIKeyV2");
} catch (err) {
console.error(err);
createNotification({
text: "Failed to delete API Key V2",
type: "error"
});
}
}
return (
<div className="mb-6 p-4 bg-mineshaft-900 rounded-lg border border-mineshaft-600">
<div className="flex justify-between mb-8">
<p className="text-xl font-semibold text-mineshaft-100">
API Keys V2 (Beta)
</p>
<Button
colorSchema="secondary"
type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => handlePopUpOpen("apiKeyV2")}
>
Add API Key
</Button>
</div>
<APIKeyV2Table
handlePopUpOpen={handlePopUpOpen}
/>
<APIKeyV2Modal
popUp={popUp}
handlePopUpToggle={handlePopUpToggle}
/>
<DeleteActionModal
isOpen={popUp.deleteAPIKeyV2.isOpen}
title={`Are you sure want to delete ${
(popUp?.deleteAPIKeyV2?.data as { name: string })?.name || ""
}?`}
onChange={(isOpen) => handlePopUpToggle("deleteAPIKeyV2", isOpen)}
deleteKey="confirm"
onDeleteApproved={() =>
onDeleteAPIKeyDataSubmit(
(popUp?.deleteAPIKeyV2?.data as { apiKeyDataId: string })?.apiKeyDataId
)
}
/>
</div>
);
}

View File

@ -1,98 +0,0 @@
import { faKey, faPencil, faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { format } from "date-fns";
import {
EmptyState,
IconButton,
Table,
TableContainer,
TableSkeleton,
TBody,
Td,
Th,
THead,
Tr
} from "@app/components/v2";
import { useGetMyAPIKeysV2 } from "@app/hooks/api";
import { UsePopUpState } from "@app/hooks/usePopUp";
type Props = {
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["deleteAPIKeyV2", "apiKeyV2"]>,
data?: {
apiKeyDataId?: string;
name?: string;
}
) => void;
};
export const APIKeyV2Table = ({ handlePopUpOpen }: Props) => {
const { data, isLoading } = useGetMyAPIKeysV2();
return (
<TableContainer>
<Table>
<THead>
<Tr>
<Th className="">Name</Th>
<Th className="">Last Used</Th>
<Th className="">Created At</Th>
<Th className="w-5" />
</Tr>
</THead>
<TBody>
{isLoading && <TableSkeleton columns={4} innerKey="api-keys-v2" />}
{!isLoading &&
data &&
data.length > 0 &&
data.map(({ id, name, lastUsed, createdAt }) => {
return (
<Tr className="h-10" key={`api-key-v2-${id}`}>
<Td>{name}</Td>
<Td>{lastUsed ? format(new Date(lastUsed), "yyyy-MM-dd") : "-"}</Td>
<Td>{format(new Date(createdAt), "yyyy-MM-dd")}</Td>
<Td className="flex justify-end">
<IconButton
onClick={async () => {
handlePopUpOpen("apiKeyV2", {
apiKeyDataId: id,
name
});
}}
size="lg"
colorSchema="primary"
variant="plain"
ariaLabel="update"
>
<FontAwesomeIcon icon={faPencil} />
</IconButton>
<IconButton
onClick={() => {
handlePopUpOpen("deleteAPIKeyV2", {
apiKeyDataId: id
});
}}
size="lg"
colorSchema="danger"
variant="plain"
ariaLabel="update"
className="ml-4"
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>
</Td>
</Tr>
);
})}
{!isLoading && data && data?.length === 0 && (
<Tr>
<Td colSpan={4}>
<EmptyState title="No API key v2 on file" icon={faKey} />
</Td>
</Tr>
)}
</TBody>
</Table>
</TableContainer>
);
};

View File

@ -1 +0,0 @@
export { APIKeyV2Section } from "./APIKeyV2Section";

View File

@ -1,11 +1,5 @@
import { APIKeySection } from "../APIKeySection";
// import { APIKeyV2Section } from "../APIKeyV2Section";
export const PersonalAPIKeyTab = () => {
return (
<>
{/* <APIKeyV2Section /> */}
<APIKeySection />
</>
);
}
return <APIKeySection />;
};

View File

@ -1,44 +1,68 @@
import { Fragment } from "react"
import { Tab } from "@headlessui/react"
import { Fragment } from "react";
import Link from "next/link";
import { faWarning } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Tab } from "@headlessui/react";
import { PersonalAPIKeyTab } from "../PersonalAPIKeyTab";
import { PersonalAuthTab } from "../PersonalAuthTab";
import { PersonalGeneralTab } from "../PersonalGeneralTab";
const tabs = [
{ name: "General", key: "tab-account-general" },
{ name: "Authentication", key: "tab-account-auth" },
{ name: "API Keys", key: "tab-account-api-keys" }
{ name: "General", key: "tab-account-general" },
{ name: "Authentication", key: "tab-account-auth" },
{ name: "API Keys", key: "tab-account-api-keys" }
];
export const PersonalTabGroup = () => {
return (
<Tab.Group>
<Tab.List className="mb-4 border-b-2 border-mineshaft-800 w-full">
{tabs.map((tab) => (
<Tab as={Fragment} key={tab.key}>
{({ selected }) => (
<button
type="button"
className={`w-30 py-2 mx-2 mr-4 font-medium text-sm outline-none ${selected ? "border-b border-white text-white" : "text-mineshaft-400"}`}
>
{tab.name}
</button>
)}
</Tab>
))}
</Tab.List>
<Tab.Panels>
<Tab.Panel>
<PersonalGeneralTab />
</Tab.Panel>
<Tab.Panel>
<PersonalAuthTab />
</Tab.Panel>
<Tab.Panel>
<PersonalAPIKeyTab />
</Tab.Panel>
</Tab.Panels>
</Tab.Group>
);
}
return (
<Tab.Group>
<Tab.List className="mb-4 w-full border-b-2 border-mineshaft-800">
{tabs.map((tab) => (
<Tab as={Fragment} key={tab.key}>
{({ selected }) => (
<button
type="button"
className={`w-30 mx-2 mr-4 py-2 text-sm font-medium outline-none ${
selected ? "border-b border-white text-white" : "text-mineshaft-400"
}`}
>
{tab.name}
</button>
)}
</Tab>
))}
</Tab.List>
<Tab.Panels>
<Tab.Panel>
<PersonalGeneralTab />
</Tab.Panel>
<Tab.Panel>
<PersonalAuthTab />
</Tab.Panel>
<Tab.Panel>
<div className="space-y-3">
<div className="mt-4 flex w-full flex-row items-center rounded-md border border-primary-600/70 bg-primary/[.07] p-4 text-base text-white">
<FontAwesomeIcon icon={faWarning} className="pr-6 text-4xl text-white/80" />
<div className="flex w-full flex-col text-sm">
<span className="mb-4 text-lg font-semibold">Deprecation Notice</span>
<p>
API Keys are deprecated and will be removed in the future.
<br /> Please use Machine Identity authentication for your applications and
services.
</p>
<Link href="https://infisical.com/docs/documentation/platform/identities/overview">
<a target="_blank" className="font-semibold text-primary-400">
Learn more about Machine Identities
</a>
</Link>
</div>
</div>
<PersonalAPIKeyTab />
</div>
</Tab.Panel>
</Tab.Panels>
</Tab.Group>
);
};