From f0edcd1f0f1d52f386df9929be95fe2657e885cd Mon Sep 17 00:00:00 2001 From: x032205 Date: Thu, 16 Oct 2025 18:12:03 -0400 Subject: [PATCH 001/146] feat(pam): account credential rotation --- .../20251015042917_pam-account-rotation.ts | 43 +++++++ backend/src/db/schemas/pam-accounts.ts | 5 +- backend/src/db/schemas/pam-resources.ts | 4 +- .../pam-account-endpoints.ts | 12 +- .../pam-resource-endpoints.ts | 2 + .../ee/services/audit-log/audit-log-types.ts | 16 +++ .../services/pam-account/pam-account-dal.ts | 16 ++- .../pam-account/pam-account-service.ts | 114 +++++++++++++++++- .../services/pam-account/pam-account-types.ts | 5 +- .../services/pam-resource/pam-resource-fns.ts | 10 +- .../pam-resource/pam-resource-schemas.ts | 9 +- .../pam-resource/pam-resource-service.ts | 60 ++++++++- .../pam-resource/pam-resource-types.ts | 7 +- .../postgres/postgres-resource-schemas.ts | 14 ++- .../shared/sql/sql-resource-factory.ts | 67 +++++++++- backend/src/queue/queue-service.ts | 10 +- backend/src/server/routes/index.ts | 10 +- .../pam-account-rotation-queue.ts | 61 ++++++++++ .../src/hooks/api/pam/types/base-account.ts | 3 + .../hooks/api/pam/types/postgres-resource.ts | 1 + .../PamAccountForm/PamAccountForm.tsx | 10 +- .../PamAccountForm/PostgresAccountForm.tsx | 4 +- .../PamAccountForm/RotateAccountFields.tsx | 71 +++++++++++ .../PamResourceForm/PostgresResourceForm.tsx | 6 +- .../shared/SqlRotateAccountFields.tsx | 64 ++++++++++ 25 files changed, 588 insertions(+), 36 deletions(-) create mode 100644 backend/src/db/migrations/20251015042917_pam-account-rotation.ts create mode 100644 backend/src/services/pam-account-rotation/pam-account-rotation-queue.ts create mode 100644 frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/RotateAccountFields.tsx create mode 100644 frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx diff --git a/backend/src/db/migrations/20251015042917_pam-account-rotation.ts b/backend/src/db/migrations/20251015042917_pam-account-rotation.ts new file mode 100644 index 000000000..cd9a7d19a --- /dev/null +++ b/backend/src/db/migrations/20251015042917_pam-account-rotation.ts @@ -0,0 +1,43 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; + +export async function up(knex: Knex): Promise { + if ( + !(await knex.schema.hasColumn(TableName.PamAccount, "rotationEnabled")) && + !(await knex.schema.hasColumn(TableName.PamAccount, "rotationIntervalSeconds")) && + !(await knex.schema.hasColumn(TableName.PamAccount, "lastRotatedAt")) + ) { + await knex.schema.alterTable(TableName.PamAccount, (t) => { + t.boolean("rotationEnabled").notNullable().defaultTo(false); + t.integer("rotationIntervalSeconds").notNullable().defaultTo(2592000); + t.timestamp("lastRotatedAt").nullable(); + }); + } + + if (!(await knex.schema.hasColumn(TableName.PamResource, "encryptedRotationAccountCredentials"))) { + await knex.schema.alterTable(TableName.PamResource, (t) => { + t.binary("encryptedRotationAccountCredentials").nullable(); + }); + } +} + +export async function down(knex: Knex): Promise { + if (await knex.schema.hasColumn(TableName.PamResource, "encryptedRotationAccountCredentials")) { + await knex.schema.alterTable(TableName.PamResource, (t) => { + t.dropColumn("encryptedRotationAccountCredentials"); + }); + } + + if ( + (await knex.schema.hasColumn(TableName.PamAccount, "rotationEnabled")) && + (await knex.schema.hasColumn(TableName.PamAccount, "rotationIntervalSeconds")) && + (await knex.schema.hasColumn(TableName.PamAccount, "lastRotatedAt")) + ) { + await knex.schema.alterTable(TableName.PamAccount, (t) => { + t.dropColumn("lastRotatedAt"); + t.dropColumn("rotationIntervalSeconds"); + t.dropColumn("rotationEnabled"); + }); + } +} diff --git a/backend/src/db/schemas/pam-accounts.ts b/backend/src/db/schemas/pam-accounts.ts index 5a9a45617..9bcfa5cec 100644 --- a/backend/src/db/schemas/pam-accounts.ts +++ b/backend/src/db/schemas/pam-accounts.ts @@ -18,7 +18,10 @@ export const PamAccountsSchema = z.object({ description: z.string().nullable().optional(), encryptedCredentials: zodBuffer, createdAt: z.date(), - updatedAt: z.date() + updatedAt: z.date(), + rotationEnabled: z.boolean().default(false), + rotationIntervalSeconds: z.number().default(2592000), + lastRotatedAt: z.date().nullable().optional() }); export type TPamAccounts = z.infer; diff --git a/backend/src/db/schemas/pam-resources.ts b/backend/src/db/schemas/pam-resources.ts index d34017d0f..929a31c79 100644 --- a/backend/src/db/schemas/pam-resources.ts +++ b/backend/src/db/schemas/pam-resources.ts @@ -17,7 +17,9 @@ export const PamResourcesSchema = z.object({ resourceType: z.string(), encryptedConnectionDetails: zodBuffer, createdAt: z.date(), - updatedAt: z.date() + updatedAt: z.date(), + encryptedRotationAccountDetails: zodBuffer.nullable().optional(), + encryptedRotationAccountCredentials: zodBuffer.nullable().optional() }); export type TPamResources = z.infer; diff --git a/backend/src/ee/routes/v1/pam-account-routers/pam-account-endpoints.ts b/backend/src/ee/routes/v1/pam-account-routers/pam-account-endpoints.ts index 0ed7e238a..dccaaa8ca 100644 --- a/backend/src/ee/routes/v1/pam-account-routers/pam-account-endpoints.ts +++ b/backend/src/ee/routes/v1/pam-account-routers/pam-account-endpoints.ts @@ -22,11 +22,15 @@ export const registerPamResourceEndpoints = ({ folderId?: C["folderId"]; name: C["name"]; description?: C["description"]; + rotationEnabled: C["rotationEnabled"]; + rotationIntervalSeconds: C["rotationIntervalSeconds"]; }>; updateAccountSchema: z.ZodType<{ credentials?: C["credentials"]; name?: C["name"]; description?: C["description"]; + rotationEnabled?: C["rotationEnabled"]; + rotationIntervalSeconds?: C["rotationIntervalSeconds"]; }>; accountResponseSchema: z.ZodTypeAny; }) => { @@ -60,7 +64,9 @@ export const registerPamResourceEndpoints = ({ resourceType, folderId: req.body.folderId, name: req.body.name, - description: req.body.description + description: req.body.description, + rotationEnabled: req.body.rotationEnabled, + rotationIntervalSeconds: req.body.rotationIntervalSeconds } } }); @@ -108,7 +114,9 @@ export const registerPamResourceEndpoints = ({ resourceId: account.resourceId, resourceType, name: req.body.name, - description: req.body.description + description: req.body.description, + rotationEnabled: req.body.rotationEnabled, + rotationIntervalSeconds: req.body.rotationIntervalSeconds } } }); diff --git a/backend/src/ee/routes/v1/pam-resource-routers/pam-resource-endpoints.ts b/backend/src/ee/routes/v1/pam-resource-routers/pam-resource-endpoints.ts index 776de8e48..ffbeae5c0 100644 --- a/backend/src/ee/routes/v1/pam-resource-routers/pam-resource-endpoints.ts +++ b/backend/src/ee/routes/v1/pam-resource-routers/pam-resource-endpoints.ts @@ -21,11 +21,13 @@ export const registerPamResourceEndpoints = ({ connectionDetails: T["connectionDetails"]; gatewayId: T["gatewayId"]; name: T["name"]; + rotationAccountCredentials?: T["rotationAccountCredentials"]; }>; updateResourceSchema: z.ZodType<{ connectionDetails?: T["connectionDetails"]; gatewayId?: T["gatewayId"]; name?: T["name"]; + rotationAccountCredentials?: T["rotationAccountCredentials"]; }>; resourceResponseSchema: z.ZodTypeAny; }) => { diff --git a/backend/src/ee/services/audit-log/audit-log-types.ts b/backend/src/ee/services/audit-log/audit-log-types.ts index bc50283d4..ff2dafa9f 100644 --- a/backend/src/ee/services/audit-log/audit-log-types.ts +++ b/backend/src/ee/services/audit-log/audit-log-types.ts @@ -515,6 +515,7 @@ export enum EventType { PAM_ACCOUNT_CREATE = "pam-account-create", PAM_ACCOUNT_UPDATE = "pam-account-update", PAM_ACCOUNT_DELETE = "pam-account-delete", + PAM_ACCOUNT_CREDENTIAL_ROTATION = "pam-account-credential-rotation", PAM_RESOURCE_LIST = "pam-resource-list", PAM_RESOURCE_GET = "pam-resource-get", PAM_RESOURCE_CREATE = "pam-resource-create", @@ -3795,6 +3796,8 @@ interface PamAccountCreateEvent { folderId?: string | null; name: string; description?: string | null; + rotationEnabled: boolean; + rotationIntervalSeconds: number; }; } @@ -3806,6 +3809,8 @@ interface PamAccountUpdateEvent { resourceType: string; name?: string; description?: string | null; + rotationEnabled?: boolean; + rotationIntervalSeconds?: number; }; } @@ -3819,6 +3824,16 @@ interface PamAccountDeleteEvent { }; } +interface PamAccountCredentialRotationEvent { + type: EventType.PAM_ACCOUNT_CREDENTIAL_ROTATION; + metadata: { + accountName: string; + accountId: string; + resourceId: string; + resourceType: string; + }; +} + interface PamResourceListEvent { type: EventType.PAM_RESOURCE_LIST; metadata: { @@ -4209,6 +4224,7 @@ export type Event = | PamAccountCreateEvent | PamAccountUpdateEvent | PamAccountDeleteEvent + | PamAccountCredentialRotationEvent | PamResourceListEvent | PamResourceGetEvent | PamResourceCreateEvent diff --git a/backend/src/ee/services/pam-account/pam-account-dal.ts b/backend/src/ee/services/pam-account/pam-account-dal.ts index b62e940fe..c422c2b1d 100644 --- a/backend/src/ee/services/pam-account/pam-account-dal.ts +++ b/backend/src/ee/services/pam-account/pam-account-dal.ts @@ -39,5 +39,19 @@ export const pamAccountDALFactory = (db: TDbClient) => { })); }; - return { ...orm, findWithResourceDetails }; + const findAccountsDueForRotation = async (tx?: Knex) => { + const dbClient = tx || db.replicaNode(); + + const accounts = await dbClient(TableName.PamAccount) + .innerJoin(TableName.PamResource, `${TableName.PamAccount}.resourceId`, `${TableName.PamResource}.id`) + .whereNotNull(`${TableName.PamResource}.encryptedRotationAccountCredentials`) + .whereRaw( + `COALESCE("${TableName.PamAccount}"."lastRotatedAt", "${TableName.PamAccount}"."createdAt") + "${TableName.PamAccount}"."rotationIntervalSeconds" * interval '1 second' < NOW()` + ) + .select(selectAllTableCols(TableName.PamAccount)); + + return accounts; + }; + + return { ...orm, findWithResourceDetails, findAccountsDueForRotation }; }; diff --git a/backend/src/ee/services/pam-account/pam-account-service.ts b/backend/src/ee/services/pam-account/pam-account-service.ts index e9ea76e8c..6146c1a13 100644 --- a/backend/src/ee/services/pam-account/pam-account-service.ts +++ b/backend/src/ee/services/pam-account/pam-account-service.ts @@ -11,12 +11,14 @@ import { } from "@app/ee/services/permission/project-permission"; import { DatabaseErrorCode } from "@app/lib/error-codes"; import { BadRequestError, DatabaseError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors"; +import { logger } from "@app/lib/logger"; import { OrgServiceActor } from "@app/lib/types"; import { ActorType } from "@app/services/auth/auth-type"; import { TKmsServiceFactory } from "@app/services/kms/kms-service"; import { TProjectDALFactory } from "@app/services/project/project-dal"; import { TUserDALFactory } from "@app/services/user/user-dal"; +import { EventType, TAuditLogServiceFactory } from "../audit-log/audit-log-types"; import { TGatewayV2ServiceFactory } from "../gateway-v2/gateway-v2-service"; import { TLicenseServiceFactory } from "../license/license-service"; import { TPamFolderDALFactory } from "../pam-folder/pam-folder-dal"; @@ -45,10 +47,12 @@ type TPamAccountServiceFactoryDep = { "getPAMConnectionDetails" | "getPlatformConnectionDetailsByGatewayId" >; userDAL: TUserDALFactory; + auditLogService: Pick; }; - export type TPamAccountServiceFactory = ReturnType; +const ROTATION_CONCURRENCY_LIMIT = 10; + export const pamAccountServiceFactory = ({ pamResourceDAL, pamSessionDAL, @@ -59,10 +63,19 @@ export const pamAccountServiceFactory = ({ permissionService, licenseService, kmsService, - gatewayV2Service + gatewayV2Service, + auditLogService }: TPamAccountServiceFactoryDep) => { const create = async ( - { credentials, resourceId, name, description, folderId }: TCreateAccountDTO, + { + credentials, + resourceId, + name, + description, + folderId, + rotationEnabled, + rotationIntervalSeconds + }: TCreateAccountDTO, actor: OrgServiceActor ) => { const orgLicensePlan = await licenseService.getPlan(actor.orgId); @@ -84,6 +97,10 @@ export const pamAccountServiceFactory = ({ actionProjectType: ActionProjectType.PAM }); + if (!resource.encryptedRotationAccountCredentials && rotationEnabled) { + throw new NotFoundError({ message: "Rotation credentials are not configured for this account's resource" }); + } + const accountPath = await getFullPamFolderPath({ pamFolderDAL, folderId, @@ -126,7 +143,9 @@ export const pamAccountServiceFactory = ({ encryptedCredentials, name, description, - folderId + folderId, + rotationEnabled, + rotationIntervalSeconds }); return { @@ -145,7 +164,7 @@ export const pamAccountServiceFactory = ({ }; const updateById = async ( - { accountId, credentials, description, name }: TUpdateAccountDTO, + { accountId, credentials, description, name, rotationEnabled, rotationIntervalSeconds }: TUpdateAccountDTO, actor: OrgServiceActor ) => { const orgLicensePlan = await licenseService.getPlan(actor.orgId); @@ -195,6 +214,17 @@ export const pamAccountServiceFactory = ({ updateDoc.description = description; } + if (rotationEnabled !== undefined) { + if (!resource.encryptedRotationAccountCredentials && rotationEnabled) { + throw new NotFoundError({ message: "Rotation credentials are not configured for this account's resource" }); + } + updateDoc.rotationEnabled = rotationEnabled; + } + + if (rotationIntervalSeconds !== undefined) { + updateDoc.rotationIntervalSeconds = rotationIntervalSeconds; + } + if (credentials !== undefined) { const connectionDetails = await decryptResourceConnectionDetails({ projectId: account.projectId, @@ -516,12 +546,84 @@ export const pamAccountServiceFactory = ({ }; }; + const rotateAllDueAccounts = async () => { + const accounts = await pamAccountDAL.findAccountsDueForRotation(); + + for (let i = 0; i < accounts.length; i += ROTATION_CONCURRENCY_LIMIT) { + const batch = accounts.slice(i, i + ROTATION_CONCURRENCY_LIMIT); + + const rotationPromises = batch.map(async (account) => { + try { + const resource = await pamResourceDAL.findById(account.resourceId); + if (!resource || !resource.encryptedRotationAccountCredentials) return; + + const { connectionDetails, rotationAccountCredentials, gatewayId, resourceType } = await decryptResource( + resource, + account.projectId, + kmsService + ); + + if (!rotationAccountCredentials) return; + + const accountCredentials = await decryptAccountCredentials({ + encryptedCredentials: account.encryptedCredentials, + projectId: account.projectId, + kmsService + }); + + const factory = PAM_RESOURCE_FACTORY_MAP[resourceType as PamResource]( + resourceType as PamResource, + connectionDetails, + gatewayId, + gatewayV2Service + ); + + const newCredentials = await factory.rotateAccountCredentials(rotationAccountCredentials, accountCredentials); + + const encryptedCredentials = await encryptAccountCredentials({ + credentials: newCredentials, + projectId: account.projectId, + kmsService + }); + + await pamAccountDAL.updateById(account.id, { + encryptedCredentials, + lastRotatedAt: new Date() + }); + + await auditLogService.createAuditLog({ + projectId: account.projectId, + actor: { + type: ActorType.PLATFORM, + metadata: {} + }, + event: { + type: EventType.PAM_ACCOUNT_CREDENTIAL_ROTATION, + metadata: { + accountId: account.id, + accountName: account.name, + resourceId: resource.id, + resourceType: resource.resourceType + } + } + }); + } catch (error) { + logger.error(error, `Failed to rotate credentials for account ${account.id}`); + } + }); + + // eslint-disable-next-line no-await-in-loop + await Promise.all(rotationPromises); + } + }; + return { create, updateById, deleteById, list, access, - getSessionCredentials + getSessionCredentials, + rotateAllDueAccounts }; }; diff --git a/backend/src/ee/services/pam-account/pam-account-types.ts b/backend/src/ee/services/pam-account/pam-account-types.ts index 514d7d780..4bbccc6fa 100644 --- a/backend/src/ee/services/pam-account/pam-account-types.ts +++ b/backend/src/ee/services/pam-account/pam-account-types.ts @@ -1,7 +1,10 @@ import { TPamAccount } from "../pam-resource/pam-resource-types"; // DTOs -export type TCreateAccountDTO = Pick; +export type TCreateAccountDTO = Pick< + TPamAccount, + "name" | "description" | "credentials" | "folderId" | "resourceId" | "rotationEnabled" | "rotationIntervalSeconds" +>; export type TUpdateAccountDTO = Partial> & { accountId: string; diff --git a/backend/src/ee/services/pam-resource/pam-resource-fns.ts b/backend/src/ee/services/pam-resource/pam-resource-fns.ts index 1d79e892e..9d7493e68 100644 --- a/backend/src/ee/services/pam-resource/pam-resource-fns.ts +++ b/backend/src/ee/services/pam-resource/pam-resource-fns.ts @@ -2,6 +2,7 @@ import { TPamResources } from "@app/db/schemas"; import { TKmsServiceFactory } from "@app/services/kms/kms-service"; import { KmsDataKey } from "@app/services/kms/kms-types"; +import { decryptAccountCredentials } from "../pam-account/pam-account-fns"; import { TPamResource, TPamResourceConnectionDetails } from "./pam-resource-types"; import { getPostgresResourceListItem } from "./postgres/postgres-resource-fns"; @@ -63,6 +64,13 @@ export const decryptResource = async ( encryptedConnectionDetails: resource.encryptedConnectionDetails, projectId, kmsService - }) + }), + rotationAccountCredentials: resource.encryptedRotationAccountCredentials + ? await decryptAccountCredentials({ + encryptedCredentials: resource.encryptedRotationAccountCredentials, + projectId, + kmsService + }) + : null } as TPamResource; }; diff --git a/backend/src/ee/services/pam-resource/pam-resource-schemas.ts b/backend/src/ee/services/pam-resource/pam-resource-schemas.ts index 80a50a9a4..5b0199166 100644 --- a/backend/src/ee/services/pam-resource/pam-resource-schemas.ts +++ b/backend/src/ee/services/pam-resource/pam-resource-schemas.ts @@ -6,6 +6,7 @@ import { slugSchema } from "@app/server/lib/schemas"; // Resources export const BasePamResourceSchema = PamResourcesSchema.omit({ encryptedConnectionDetails: true, + encryptedRotationAccountCredentials: true, resourceType: true }); @@ -37,10 +38,14 @@ export const BaseCreatePamAccountSchema = z.object({ resourceId: z.string().uuid(), folderId: z.string().uuid().optional(), name: slugSchema({ field: "name" }), - description: z.string().max(512).nullable().optional() + description: z.string().max(512).nullable().optional(), + rotationEnabled: z.boolean(), + rotationIntervalSeconds: z.number().min(3600) }); export const BaseUpdatePamAccountSchema = z.object({ name: slugSchema({ field: "name" }).optional(), - description: z.string().max(512).nullable().optional() + description: z.string().max(512).nullable().optional(), + rotationEnabled: z.boolean().optional(), + rotationIntervalSeconds: z.number().min(3600).optional() }); diff --git a/backend/src/ee/services/pam-resource/pam-resource-service.ts b/backend/src/ee/services/pam-resource/pam-resource-service.ts index 312795a50..1cc3ca135 100644 --- a/backend/src/ee/services/pam-resource/pam-resource-service.ts +++ b/backend/src/ee/services/pam-resource/pam-resource-service.ts @@ -10,10 +10,16 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service"; import { TGatewayV2ServiceFactory } from "../gateway-v2/gateway-v2-service"; import { TLicenseServiceFactory } from "../license/license-service"; +import { encryptAccountCredentials } from "../pam-account/pam-account-fns"; import { TPamResourceDALFactory } from "./pam-resource-dal"; import { PamResource } from "./pam-resource-enums"; import { PAM_RESOURCE_FACTORY_MAP } from "./pam-resource-factory"; -import { decryptResource, encryptResourceConnectionDetails, listResourceOptions } from "./pam-resource-fns"; +import { + decryptResource, + decryptResourceConnectionDetails, + encryptResourceConnectionDetails, + listResourceOptions +} from "./pam-resource-fns"; import { TCreateResourceDTO, TUpdateResourceDTO } from "./pam-resource-types"; type TPamResourceServiceFactoryDep = { @@ -61,7 +67,7 @@ export const pamResourceServiceFactory = ({ }; const create = async ( - { resourceType, connectionDetails, gatewayId, name, projectId }: TCreateResourceDTO, + { resourceType, connectionDetails, gatewayId, name, projectId, rotationAccountCredentials }: TCreateResourceDTO, actor: OrgServiceActor ) => { const orgLicensePlan = await licenseService.getPlan(actor.orgId); @@ -88,26 +94,42 @@ export const pamResourceServiceFactory = ({ gatewayId, gatewayV2Service ); - const validatedConnectionDetails = await factory.validateConnection(); + const validatedConnectionDetails = await factory.validateConnection(); const encryptedConnectionDetails = await encryptResourceConnectionDetails({ connectionDetails: validatedConnectionDetails, projectId, kmsService }); + let encryptedRotationAccountCredentials: Buffer | null = null; + + if (rotationAccountCredentials) { + const validatedRotationAccountCredentials = await factory.validateAccountCredentials(rotationAccountCredentials); + + encryptedRotationAccountCredentials = await encryptAccountCredentials({ + credentials: validatedRotationAccountCredentials, + projectId, + kmsService + }); + } + const resource = await pamResourceDAL.create({ resourceType, encryptedConnectionDetails, gatewayId, name, - projectId + projectId, + encryptedRotationAccountCredentials }); return decryptResource(resource, projectId, kmsService); }; - const updateById = async ({ connectionDetails, resourceId, name }: TUpdateResourceDTO, actor: OrgServiceActor) => { + const updateById = async ( + { connectionDetails, resourceId, name, rotationAccountCredentials }: TUpdateResourceDTO, + actor: OrgServiceActor + ) => { const orgLicensePlan = await licenseService.getPlan(actor.orgId); if (!orgLicensePlan.pam) { throw new BadRequestError({ @@ -151,6 +173,34 @@ export const pamResourceServiceFactory = ({ updateDoc.encryptedConnectionDetails = encryptedConnectionDetails; } + if (rotationAccountCredentials !== undefined) { + updateDoc.encryptedRotationAccountCredentials = null; + + if (rotationAccountCredentials) { + const decryptedConnectionDetails = await decryptResourceConnectionDetails({ + encryptedConnectionDetails: resource.encryptedConnectionDetails, + projectId: resource.projectId, + kmsService + }); + + const factory = PAM_RESOURCE_FACTORY_MAP[resource.resourceType as PamResource]( + resource.resourceType as PamResource, + decryptedConnectionDetails, + resource.gatewayId, + gatewayV2Service + ); + + const validatedRotationAccountCredentials = + await factory.validateAccountCredentials(rotationAccountCredentials); + + updateDoc.encryptedRotationAccountCredentials = await encryptAccountCredentials({ + credentials: validatedRotationAccountCredentials, + projectId: resource.projectId, + kmsService + }); + } + } + // If nothing was updated, return the fetched resource if (Object.keys(updateDoc).length === 0) { return decryptResource(resource, resource.projectId, kmsService); diff --git a/backend/src/ee/services/pam-resource/pam-resource-types.ts b/backend/src/ee/services/pam-resource/pam-resource-types.ts index fb1b669ed..f2016420a 100644 --- a/backend/src/ee/services/pam-resource/pam-resource-types.ts +++ b/backend/src/ee/services/pam-resource/pam-resource-types.ts @@ -18,7 +18,7 @@ export type TPamAccountCredentials = TPostgresAccountCredentials; // Resource DTOs export type TCreateResourceDTO = Pick< TPamResource, - "name" | "connectionDetails" | "resourceType" | "gatewayId" | "projectId" + "name" | "connectionDetails" | "resourceType" | "gatewayId" | "projectId" | "rotationAccountCredentials" >; export type TUpdateResourceDTO = Partial> & { @@ -30,6 +30,10 @@ export type TPamResourceFactoryValidateConnection = ( credentials: C ) => Promise; +export type TPamResourceFactoryRotateAccountCredentials = ( + rotationAccountCredentials: C, + currentCredentials: C +) => Promise; export type TPamResourceFactory = ( resourceType: PamResource, @@ -39,4 +43,5 @@ export type TPamResourceFactory { validateConnection: TPamResourceFactoryValidateConnection; validateAccountCredentials: TPamResourceFactoryValidateAccountCredentials; + rotateAccountCredentials: TPamResourceFactoryRotateAccountCredentials; }; diff --git a/backend/src/ee/services/pam-resource/postgres/postgres-resource-schemas.ts b/backend/src/ee/services/pam-resource/postgres/postgres-resource-schemas.ts index a97e3f2e7..f383f521a 100644 --- a/backend/src/ee/services/pam-resource/postgres/postgres-resource-schemas.ts +++ b/backend/src/ee/services/pam-resource/postgres/postgres-resource-schemas.ts @@ -15,13 +15,15 @@ import { BaseSqlResourceConnectionDetailsSchema } from "../shared/sql/sql-resource-schemas"; -// Resources export const PostgresResourceConnectionDetailsSchema = BaseSqlResourceConnectionDetailsSchema; +export const PostgresAccountCredentialsSchema = BaseSqlAccountCredentialsSchema; +// Resources const BasePostgresResourceSchema = BasePamResourceSchema.extend({ resourceType: z.literal(PamResource.Postgres) }); export const PostgresResourceSchema = BasePostgresResourceSchema.extend({ - connectionDetails: PostgresResourceConnectionDetailsSchema + connectionDetails: PostgresResourceConnectionDetailsSchema, + rotationAccountCredentials: PostgresAccountCredentialsSchema.nullable().optional() }); export const PostgresResourceListItemSchema = z.object({ @@ -30,16 +32,16 @@ export const PostgresResourceListItemSchema = z.object({ }); export const CreatePostgresResourceSchema = BaseCreatePamResourceSchema.extend({ - connectionDetails: PostgresResourceConnectionDetailsSchema + connectionDetails: PostgresResourceConnectionDetailsSchema, + rotationAccountCredentials: PostgresAccountCredentialsSchema.nullable().optional() }); export const UpdatePostgresResourceSchema = BaseUpdatePamResourceSchema.extend({ - connectionDetails: PostgresResourceConnectionDetailsSchema.optional() + connectionDetails: PostgresResourceConnectionDetailsSchema.optional(), + rotationAccountCredentials: PostgresAccountCredentialsSchema.nullable().optional() }); // Accounts -export const PostgresAccountCredentialsSchema = BaseSqlAccountCredentialsSchema; - export const PostgresAccountSchema = BasePamAccountSchema.extend({ credentials: PostgresAccountCredentialsSchema }); diff --git a/backend/src/ee/services/pam-resource/shared/sql/sql-resource-factory.ts b/backend/src/ee/services/pam-resource/shared/sql/sql-resource-factory.ts index 74a2c74ae..73defd6e6 100644 --- a/backend/src/ee/services/pam-resource/shared/sql/sql-resource-factory.ts +++ b/backend/src/ee/services/pam-resource/shared/sql/sql-resource-factory.ts @@ -6,9 +6,14 @@ import { TGatewayV2ServiceFactory } from "@app/ee/services/gateway-v2/gateway-v2 import { BadRequestError } from "@app/lib/errors"; import { GatewayProxyProtocol } from "@app/lib/gateway"; import { withGatewayV2Proxy } from "@app/lib/gateway-v2/gateway-v2"; +import { alphaNumericNanoId } from "@app/lib/nanoid"; import { PamResource } from "../../pam-resource-enums"; -import { TPamResourceFactory, TPamResourceFactoryValidateAccountCredentials } from "../../pam-resource-types"; +import { + TPamResourceFactory, + TPamResourceFactoryRotateAccountCredentials, + TPamResourceFactoryValidateAccountCredentials +} from "../../pam-resource-types"; import { TSqlAccountCredentials, TSqlResourceConnectionDetails } from "./sql-resource-types"; const EXTERNAL_REQUEST_TIMEOUT = 10 * 1000; @@ -176,8 +181,66 @@ export const sqlResourceFactory: TPamResourceFactory = async ( + rotationAccountCredentials, + currentCredentials + ) => { + try { + const newPassword = alphaNumericNanoId(32); + + await executeWithGateway( + { + connectionDetails, + gatewayId, + resourceType, + username: rotationAccountCredentials.username, + password: rotationAccountCredentials.password + }, + gatewayV2Service, + async (client) => { + switch (resourceType) { + case PamResource.Postgres: + await client.raw(`ALTER USER ?? WITH PASSWORD '${newPassword}'`, [currentCredentials.username]); + break; + default: + throw new BadRequestError({ + message: `Password rotation for ${resourceType as PamResource} is not supported.` + }); + } + } + ); + + return { username: currentCredentials.username, password: newPassword }; + } catch (error) { + if (error instanceof BadRequestError) { + if (error.message === `password authentication failed for user "${rotationAccountCredentials.username}"`) { + throw new BadRequestError({ + message: "Management credentials invalid: Username or password incorrect" + }); + } + + if (error.message.includes("permission denied")) { + throw new BadRequestError({ + message: `Management credentials lack permission to rotate password for user "${currentCredentials.username}"` + }); + } + + if (error.message === "Connection terminated unexpectedly") { + throw new BadRequestError({ + message: "Connection terminated unexpectedly. Verify that host and port are correct" + }); + } + } + + throw new BadRequestError({ + message: `Unable to rotate account credentials for ${resourceType}: ${(error as Error).message || String(error)}` + }); + } + }; + return { validateConnection, - validateAccountCredentials + validateAccountCredentials, + rotateAccountCredentials }; }; diff --git a/backend/src/queue/queue-service.ts b/backend/src/queue/queue-service.ts index 7f45e3821..9d8c472f4 100644 --- a/backend/src/queue/queue-service.ts +++ b/backend/src/queue/queue-service.ts @@ -77,7 +77,8 @@ export enum QueueName { DailyReminders = "daily-reminders", SecretReminderMigration = "secret-reminder-migration", UserNotification = "user-notification", - HealthAlert = "health-alert" + HealthAlert = "health-alert", + PamAccountRotation = "pam-account-rotation" } export enum QueueJobs { @@ -126,7 +127,8 @@ export enum QueueJobs { DailyReminders = "daily-reminders", SecretReminderMigration = "secret-reminder-migration", UserNotification = "user-notification-job", - HealthAlert = "health-alert" + HealthAlert = "health-alert", + PamAccountRotation = "pam-account-rotation" } export type TQueueJobTypes = { @@ -357,6 +359,10 @@ export type TQueueJobTypes = { name: QueueJobs.HealthAlert; payload: undefined; }; + [QueueName.PamAccountRotation]: { + name: QueueJobs.PamAccountRotation; + payload: undefined; + }; }; const SECRET_SCANNING_JOBS = [ diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index e95dd501c..448564704 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -250,6 +250,7 @@ import { orgDALFactory } from "@app/services/org/org-dal"; import { orgServiceFactory } from "@app/services/org/org-service"; import { orgAdminServiceFactory } from "@app/services/org-admin/org-admin-service"; import { orgMembershipDALFactory } from "@app/services/org-membership/org-membership-dal"; +import { pamAccountRotationServiceFactory } from "@app/services/pam-account-rotation/pam-account-rotation-queue"; import { dailyExpiringPkiItemAlertQueueServiceFactory } from "@app/services/pki-alert/expiring-pki-item-alert-queue"; import { pkiAlertDALFactory } from "@app/services/pki-alert/pki-alert-dal"; import { pkiAlertServiceFactory } from "@app/services/pki-alert/pki-alert-service"; @@ -2193,7 +2194,13 @@ export const registerRoutes = async ( pamSessionDAL, permissionService, projectDAL, - userDAL + userDAL, + auditLogService + }); + + const pamAccountRotation = pamAccountRotationServiceFactory({ + queueService, + pamAccountService }); const pamSessionService = pamSessionServiceFactory({ @@ -2220,6 +2227,7 @@ export const registerRoutes = async ( await dailyResourceCleanUp.init(); await healthAlert.init(); await pkiSyncCleanup.init(); + await pamAccountRotation.init(); await dailyReminderQueueService.startDailyRemindersJob(); await dailyReminderQueueService.startSecretReminderMigrationJob(); await dailyExpiringPkiItemAlert.startSendingAlerts(); diff --git a/backend/src/services/pam-account-rotation/pam-account-rotation-queue.ts b/backend/src/services/pam-account-rotation/pam-account-rotation-queue.ts new file mode 100644 index 000000000..fb265ac56 --- /dev/null +++ b/backend/src/services/pam-account-rotation/pam-account-rotation-queue.ts @@ -0,0 +1,61 @@ +import { TPamAccountServiceFactory } from "@app/ee/services/pam-account/pam-account-service"; +import { getConfig } from "@app/lib/config/env"; +import { logger } from "@app/lib/logger"; +import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue"; + +type TPamAccountRotationServiceFactoryDep = { + queueService: TQueueServiceFactory; + pamAccountService: Pick; +}; + +export type TPamAccountRotationServiceFactory = ReturnType; + +export const pamAccountRotationServiceFactory = ({ + queueService, + pamAccountService +}: TPamAccountRotationServiceFactoryDep) => { + const appCfg = getConfig(); + + const init = async () => { + if (appCfg.isSecondaryInstance) { + return; + } + + await queueService.stopRepeatableJob( + QueueName.PamAccountRotation, + QueueJobs.PamAccountRotation, + { pattern: "0 * * * *", utc: true }, + QueueName.PamAccountRotation // job id + ); + + await queueService.startPg( + QueueJobs.PamAccountRotation, + async () => { + try { + logger.info(`${QueueName.PamAccountRotation}: pam account rotation task started`); + await pamAccountService.rotateAllDueAccounts(); + logger.info(`${QueueName.PamAccountRotation}: pam account rotation task completed`); + } catch (error) { + logger.error(error, `${QueueName.PamAccountRotation}: pam account rotation failed`); + throw error; + } + }, + { + batchSize: 1, + workerCount: 1, + pollingIntervalSeconds: 1 // 5 * 60 + } + ); + + await queueService.schedulePg( + QueueJobs.PamAccountRotation, + "0 * * * *", // Schedule to run every hour + undefined, + { tz: "UTC" } + ); + }; + + return { + init + }; +}; diff --git a/frontend/src/hooks/api/pam/types/base-account.ts b/frontend/src/hooks/api/pam/types/base-account.ts index 9f45b1a4a..ec94d51b2 100644 --- a/frontend/src/hooks/api/pam/types/base-account.ts +++ b/frontend/src/hooks/api/pam/types/base-account.ts @@ -12,6 +12,9 @@ export interface TBasePamAccount { }; name: string; description?: string | null; + rotationEnabled: boolean; + rotationIntervalSeconds: number; + lastRotatedAt?: string | null; createdAt: string; updatedAt: string; } diff --git a/frontend/src/hooks/api/pam/types/postgres-resource.ts b/frontend/src/hooks/api/pam/types/postgres-resource.ts index 513610be1..b1b5b7487 100644 --- a/frontend/src/hooks/api/pam/types/postgres-resource.ts +++ b/frontend/src/hooks/api/pam/types/postgres-resource.ts @@ -6,6 +6,7 @@ import { TBasePamResource } from "./base-resource"; // Resources export type TPostgresResource = TBasePamResource & { resourceType: PamResourceType.Postgres } & { connectionDetails: TBaseSqlConnectionDetails; + rotationAccountCredentials?: TBaseSqlCredentials | null; }; // Accounts diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PamAccountForm.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PamAccountForm.tsx index ead2b06e1..bb64e33c0 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PamAccountForm.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PamAccountForm.tsx @@ -37,7 +37,10 @@ const CreateForm = ({ console.log({ folderId }); const onSubmit = async ( - formData: DiscriminativePick + formData: DiscriminativePick< + TPamAccount, + "name" | "description" | "credentials" | "rotationEnabled" | "rotationIntervalSeconds" + > ) => { try { const account = await createPamAccount.mutateAsync({ @@ -74,7 +77,10 @@ const UpdateForm = ({ account, onComplete }: UpdateFormProps) => { const updatePamAccount = useUpdatePamAccount(); const onSubmit = async ( - formData: DiscriminativePick + formData: DiscriminativePick< + TPamAccount, + "name" | "description" | "credentials" | "rotationEnabled" | "rotationIntervalSeconds" + > ) => { try { const updatedAccount = await updatePamAccount.mutateAsync({ diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx index 5bcd459aa..0033c48f3 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx @@ -8,13 +8,14 @@ import { TPostgresAccount } from "@app/hooks/api/pam"; import { BaseSqlAccountSchema } from "./shared/sql-account-schemas"; import { SqlAccountFields } from "./shared/SqlAccountFields"; import { GenericAccountFields, genericAccountFieldsSchema } from "./GenericAccountFields"; +import { RotateAccountFields, rotateAccountFieldsSchema } from "./RotateAccountFields"; type Props = { account?: TPostgresAccount; onSubmit: (formData: FormData) => Promise; }; -const formSchema = genericAccountFieldsSchema.extend({ +const formSchema = genericAccountFieldsSchema.extend(rotateAccountFieldsSchema.shape).extend({ credentials: BaseSqlAccountSchema }); @@ -50,6 +51,7 @@ export const PostgresAccountForm = ({ account, onSubmit }: Props) => { > +

@@ -257,6 +269,10 @@ export const GatewayTab = withPermission( deleteKey="confirm" onDeleteApproved={() => handleDeleteGateway()} /> + handlePopUpToggle("deployGateway", isOpen)} + /> diff --git a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployGatewayModal.tsx b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployGatewayModal.tsx new file mode 100644 index 000000000..2b8f17fe7 --- /dev/null +++ b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployGatewayModal.tsx @@ -0,0 +1,243 @@ +import { createNotification } from "@app/components/notifications"; +import { + FilterableSelect, + FormLabel, + IconButton, + Input, + Modal, + ModalContent +} from "@app/components/v2"; +import { useOrganization } from "@app/context"; +import { + useAddIdentityTokenAuth, + useCreateTokenIdentityTokenAuth, + useGetIdentityMembershipOrgs, + useGetIdentityTokenAuth +} from "@app/hooks/api"; +import { useGetRelays } from "@app/hooks/api/relays"; +import { slugSchema } from "@app/lib/schemas"; +import { faCopy, faUpRightFromSquare } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useEffect, useMemo, useState } from "react"; +import { SingleValue } from "react-select"; +import { RelayOption } from "./RelayOption"; +import { useNavigate } from "@tanstack/react-router"; +import { ROUTE_PATHS } from "@app/const/routes"; +import { twMerge } from "tailwind-merge"; + +type Props = { + isOpen: boolean; + onOpenChange: (isOpen: boolean) => void; +}; + +export const DeployGatewayModal = ({ isOpen, onOpenChange }: Props) => { + const { protocol, hostname, port } = window.location; + const portSuffix = port && port !== "80" ? `:${port}` : ""; + const siteURL = `${protocol}//${hostname}${portSuffix}`; + + const navigate = useNavigate({ + from: ROUTE_PATHS.Organization.NetworkingPage.path + }); + + const [name, setName] = useState(""); + const [relay, setRelay] = useState(null); + const [identity, setIdentity] = useState(null); + const [identityToken, setIdentityToken] = useState(""); + + useEffect(() => { + if (!isOpen) { + setName(""); + setRelay(null); + setIdentity(null); + setIdentityToken(""); + } + }, [isOpen]); + + const { data: relays, isPending: isRelaysLoading } = useGetRelays(); + + const { currentOrg } = useOrganization(); + const organizationId = currentOrg?.id || ""; + + const { data: identityMembershipOrgsData, isPending: isIdentitiesLoading } = + useGetIdentityMembershipOrgs({ + organizationId, + limit: 20000 + }); + const identityMembershipOrgs = identityMembershipOrgsData?.identityMemberships || []; + + const { mutateAsync: createToken } = useCreateTokenIdentityTokenAuth(); + const { mutateAsync: addIdentityTokenAuth } = useAddIdentityTokenAuth(); + const { refetch } = useGetIdentityTokenAuth(identity?.id ?? ""); + + useEffect(() => { + const generateToken = async () => { + if (!identity) return; + + try { + const { data: identityTokenAuth } = await refetch(); + if (!identityTokenAuth) { + await addIdentityTokenAuth({ + identityId: identity.id, + organizationId, + accessTokenTTL: 2592000, + accessTokenMaxTTL: 2592000, + accessTokenNumUsesLimit: 0, + accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }] + }); + createNotification({ + text: "Automatically enabled token authentication for this identity.", + type: "info" + }); + } + + const token = await createToken({ + identityId: identity.id, + name: "gateway token (autogenerated)" + }); + setIdentityToken(token.accessToken); + createNotification({ + text: "Automatically generated a token for this identity.", + type: "info" + }); + } catch (err) { + console.error(err); + createNotification({ + text: "Failed to generate token for identity", + type: "error" + }); + setIdentityToken(""); + } + }; + + generateToken(); + }, [identity, organizationId, refetch, addIdentityTokenAuth, createToken]); + + const handleIdentityChange = (selectedIdentity: SingleValue<{ id: string; name: string }>) => { + setIdentity(selectedIdentity); + setIdentityToken(""); + }; + + const isNameValid = useMemo(() => !name || slugSchema().safeParse(name).success, [name]); + + const isCommandReady = useMemo( + () => !!name && isNameValid && !!relay && !!identityToken, + [name, isNameValid, relay, identityToken] + ); + + const command = useMemo( + () => + `infisical gateway start --name=${name} --relay=${ + relay?.name || "" + } --domain=${siteURL} --token=${identityToken}`, + [name, relay, identityToken, siteURL] + ); + + return ( + + + + setName(e.target.value)} + placeholder="Enter gateway name..." + isError={!isNameValid} + /> + + + { + if ((newValue as SingleValue<{ id: string }>)?.id === "_create") { + navigate({ + search: { selectedTab: "relays" } + }); + return; + } + + setRelay(newValue as SingleValue<{ id: string; name: string }>); + }} + isLoading={isRelaysLoading} + options={[ + { + id: "_create", + name: "Deploy New Relay" + }, + ...(relays || []) + ]} + placeholder="Select relay..." + getOptionLabel={(option) => option.name} + getOptionValue={(option) => option.id} + components={{ Option: RelayOption }} + /> + + + + handleIdentityChange( + e as SingleValue<{ + id: string; + name: string; + }> + ) + } + isLoading={isIdentitiesLoading} + placeholder="Select identity..." + options={identityMembershipOrgs.map((membership) => membership.identity)} + getOptionValue={(option) => option.id} + getOptionLabel={(option) => option.name} + /> + + +

+ + { + navigator.clipboard.writeText(command); + + createNotification({ + text: "Command copied to clipboard", + type: "info" + }); + }} + className={twMerge("w-10", !isCommandReady && "pointer-events-none opacity-50")} + isDisabled={!isCommandReady} + > + + +
+ + Install the Infisical CLI + + + + + ); +}; diff --git a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployRelayModal.tsx b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployRelayModal.tsx new file mode 100644 index 000000000..2347c0472 --- /dev/null +++ b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployRelayModal.tsx @@ -0,0 +1,204 @@ +import { createNotification } from "@app/components/notifications"; +import { + FilterableSelect, + FormLabel, + IconButton, + Input, + Modal, + ModalContent +} from "@app/components/v2"; +import { useOrganization } from "@app/context"; +import { + useAddIdentityTokenAuth, + useCreateTokenIdentityTokenAuth, + useGetIdentityMembershipOrgs, + useGetIdentityTokenAuth +} from "@app/hooks/api"; +import { slugSchema } from "@app/lib/schemas"; +import { faCopy, faUpRightFromSquare } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useEffect, useMemo, useState } from "react"; +import { SingleValue } from "react-select"; +import { twMerge } from "tailwind-merge"; + +type Props = { + isOpen: boolean; + onOpenChange: (isOpen: boolean) => void; +}; + +export const DeployRelayModal = ({ isOpen, onOpenChange }: Props) => { + const { protocol, hostname, port } = window.location; + const portSuffix = port && port !== "80" ? `:${port}` : ""; + const siteURL = `${protocol}//${hostname}${portSuffix}`; + + const [name, setName] = useState(""); + const [host, setHost] = useState(""); + const [identity, setIdentity] = useState(null); + const [identityToken, setIdentityToken] = useState(""); + + useEffect(() => { + if (!isOpen) { + setName(""); + setHost(""); + setIdentity(null); + setIdentityToken(""); + } + }, [isOpen]); + + const { currentOrg } = useOrganization(); + const organizationId = currentOrg?.id || ""; + + const { data: identityMembershipOrgsData, isPending: isIdentitiesLoading } = + useGetIdentityMembershipOrgs({ + organizationId, + limit: 20000 + }); + const identityMembershipOrgs = identityMembershipOrgsData?.identityMemberships || []; + + const { mutateAsync: createToken } = useCreateTokenIdentityTokenAuth(); + const { mutateAsync: addIdentityTokenAuth } = useAddIdentityTokenAuth(); + const { refetch } = useGetIdentityTokenAuth(identity?.id ?? ""); + + useEffect(() => { + const generateToken = async () => { + if (!identity) return; + + try { + const { data: identityTokenAuth } = await refetch(); + if (!identityTokenAuth) { + await addIdentityTokenAuth({ + identityId: identity.id, + organizationId, + accessTokenTTL: 2592000, + accessTokenMaxTTL: 2592000, + accessTokenNumUsesLimit: 0, + accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }] + }); + createNotification({ + text: "Automatically enabled token authentication for this identity.", + type: "info" + }); + } + + const token = await createToken({ + identityId: identity.id, + name: "relay token (autogenerated)" + }); + setIdentityToken(token.accessToken); + createNotification({ + text: "Automatically generated a token for this identity.", + type: "info" + }); + } catch (err) { + console.error(err); + createNotification({ + text: "Failed to generate token for identity", + type: "error" + }); + setIdentityToken(""); + } + }; + + generateToken(); + }, [identity, organizationId, refetch, addIdentityTokenAuth, createToken]); + + const handleIdentityChange = (selectedIdentity: SingleValue<{ id: string; name: string }>) => { + setIdentity(selectedIdentity); + setIdentityToken(""); + }; + + const isNameValid = useMemo(() => !name || slugSchema().safeParse(name).success, [name]); + + const isCommandReady = useMemo( + () => !!name && !!host && isNameValid && !!identityToken, + [name, isNameValid, host, identityToken] + ); + + const command = useMemo( + () => + `infisical relay start --name=${name} --domain=${siteURL} --host=${host} --token=${identityToken}`, + [name, siteURL, host, identityToken] + ); + + return ( + + + + setName(e.target.value)} + placeholder="Enter relay name..." + isError={!isNameValid} + /> + + + setHost(e.target.value)} placeholder="0.0.0.0" /> + + + + handleIdentityChange( + e as SingleValue<{ + id: string; + name: string; + }> + ) + } + isLoading={isIdentitiesLoading} + placeholder="Select identity..." + options={identityMembershipOrgs.map((membership) => membership.identity)} + getOptionValue={(option) => option.id} + getOptionLabel={(option) => option.name} + /> + + +
+ + { + navigator.clipboard.writeText(command); + + createNotification({ + text: "Command copied to clipboard", + type: "info" + }); + }} + className={twMerge("w-10", !isCommandReady && "pointer-events-none opacity-50")} + isDisabled={!isCommandReady} + > + + +
+ + Install the Infisical CLI + + +
+
+ ); +}; diff --git a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/RelayOption.tsx b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/RelayOption.tsx new file mode 100644 index 000000000..90c9a7ebd --- /dev/null +++ b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/RelayOption.tsx @@ -0,0 +1,32 @@ +import { components, OptionProps } from "react-select"; +import { faCheckCircle } from "@fortawesome/free-regular-svg-icons"; +import { faPlus } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +export const RelayOption = ({ + isSelected, + children, + ...props +}: OptionProps<{ id: string; name: string }>) => { + const isCreateOption = props.data.id === "_create"; + + return ( + +
+ {isCreateOption ? ( +
+ + Deploy New Relay +
+ ) : ( + <> +

{children}

+ {isSelected && ( + + )} + + )} +
+
+ ); +}; diff --git a/frontend/src/pages/organization/NetworkingPage/components/NetworkingTabGroup/NetworkingTabGroup.tsx b/frontend/src/pages/organization/NetworkingPage/components/NetworkingTabGroup/NetworkingTabGroup.tsx index 956a4d1ed..dc90b7f21 100644 --- a/frontend/src/pages/organization/NetworkingPage/components/NetworkingTabGroup/NetworkingTabGroup.tsx +++ b/frontend/src/pages/organization/NetworkingPage/components/NetworkingTabGroup/NetworkingTabGroup.tsx @@ -1,14 +1,19 @@ -import { useState } from "react"; -import { useSearch } from "@tanstack/react-router"; +import { useNavigate, useSearch } from "@tanstack/react-router"; import { Tab, TabList, TabPanel, Tabs } from "@app/components/v2"; import { GatewayTab } from "../GatewayTab/GatewayTab"; import { RelayTab } from "../RelayTab/RelayTab"; +import { ROUTE_PATHS } from "@app/const/routes"; export const NetworkingTabGroup = () => { - const search = useSearch({ - from: "/_authenticate/_inject-org-details/_org-layout/organization/networking/" + const navigate = useNavigate({ + from: ROUTE_PATHS.Organization.NetworkingPage.path + }); + const selectedTab = useSearch({ + from: ROUTE_PATHS.Organization.NetworkingPage.id, + select: (el) => el.selectedTab, + structuralSharing: true }); const tabs = [ @@ -16,10 +21,14 @@ export const NetworkingTabGroup = () => { { name: "Relays", key: "relays", component: RelayTab } ]; - const [selectedTab, setSelectedTab] = useState(search.selectedTab || tabs[0].key); + const handleTabChange = (tab: string) => { + navigate({ + search: { selectedTab: tab } + }); + }; return ( - + {tabs.map((tab) => ( diff --git a/frontend/src/pages/organization/NetworkingPage/components/RelayTab/RelayTab.tsx b/frontend/src/pages/organization/NetworkingPage/components/RelayTab/RelayTab.tsx index e525b765d..2bfa8b250 100644 --- a/frontend/src/pages/organization/NetworkingPage/components/RelayTab/RelayTab.tsx +++ b/frontend/src/pages/organization/NetworkingPage/components/RelayTab/RelayTab.tsx @@ -7,6 +7,7 @@ import { faEllipsisV, faInfoCircle, faMagnifyingGlass, + faPlus, faSearch, faTrash } from "@fortawesome/free-solid-svg-icons"; @@ -16,6 +17,7 @@ import { formatRelative } from "date-fns"; import { createNotification } from "@app/components/notifications"; import { OrgPermissionCan } from "@app/components/permissions"; import { + Button, DeleteActionModal, DropdownMenu, DropdownMenuContent, @@ -41,6 +43,7 @@ import { import { withPermission } from "@app/hoc"; import { usePopUp } from "@app/hooks"; import { useDeleteRelayById, useGetRelays } from "@app/hooks/api/relays"; +import { DeployRelayModal } from "../GatewayTab/components/DeployRelayModal"; const RelayHealthStatus = ({ heartbeat }: { heartbeat?: string }) => { const heartbeatDate = heartbeat ? new Date(heartbeat) : null; @@ -66,7 +69,10 @@ export const RelayTab = withPermission( const [search, setSearch] = useState(""); const { data: relays, isPending: isRelaysLoading } = useGetRelays(); - const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp(["deleteRelay"] as const); + const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp([ + "deleteRelay", + "deployRelay" + ] as const); const deleteRelayById = useDeleteRelayById(); @@ -87,8 +93,8 @@ export const RelayTab = withPermission( return (
-
-
+
+

Relays

+
+

@@ -222,6 +236,10 @@ export const RelayTab = withPermission( deleteKey="confirm" onDeleteApproved={() => handleDeleteRelay()} /> + handlePopUpToggle("deployRelay", isOpen)} + />

diff --git a/frontend/src/pages/organization/NetworkingPage/route.tsx b/frontend/src/pages/organization/NetworkingPage/route.tsx index 906b12806..433647476 100644 --- a/frontend/src/pages/organization/NetworkingPage/route.tsx +++ b/frontend/src/pages/organization/NetworkingPage/route.tsx @@ -5,16 +5,16 @@ import { z } from "zod"; import { NetworkingPage } from "./NetworkingPage"; const NetworkingPageQueryParams = z.object({ - selectedTab: z.string().catch("") + selectedTab: z.string().catch("gateways") }); export const Route = createFileRoute( - "/_authenticate/_inject-org-details/_org-layout/organization/networking/" + "/_authenticate/_inject-org-details/_org-layout/organization/networking" )({ component: NetworkingPage, validateSearch: zodValidator(NetworkingPageQueryParams), search: { - middlewares: [stripSearchParams({ selectedTab: "" })] + middlewares: [stripSearchParams({ selectedTab: "gateways" })] }, context: () => ({ breadcrumbs: [ diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts index 1562f302d..bc92b6ef0 100644 --- a/frontend/src/routeTree.gen.ts +++ b/frontend/src/routeTree.gen.ts @@ -50,6 +50,7 @@ import { Route as adminCachingPageRouteImport } from './pages/admin/CachingPage/ import { Route as adminAuthenticationPageRouteImport } from './pages/admin/AuthenticationPage/route' import { Route as adminAccessManagementPageRouteImport } from './pages/admin/AccessManagementPage/route' import { Route as organizationProjectsPageRouteImport } from './pages/organization/ProjectsPage/route' +import { Route as organizationNetworkingPageRouteImport } from './pages/organization/NetworkingPage/route' import { Route as organizationBillingPageRouteImport } from './pages/organization/BillingPage/route' import { Route as organizationAuditLogsPageRouteImport } from './pages/organization/AuditLogsPage/route' import { Route as organizationAccessManagementPageRouteImport } from './pages/organization/AccessManagementPage/route' @@ -63,7 +64,6 @@ import { Route as organizationIdentityDetailsByIDPageRouteImport } from './pages import { Route as organizationGroupDetailsByIDPageRouteImport } from './pages/organization/GroupDetailsByIDPage/route' import { Route as organizationSettingsPageRouteImport } from './pages/organization/SettingsPage/route' import { Route as organizationSecretSharingPageRouteImport } from './pages/organization/SecretSharingPage/route' -import { Route as organizationNetworkingPageRouteImport } from './pages/organization/NetworkingPage/route' import { Route as organizationAppConnectionsAppConnectionsPageRouteImport } from './pages/organization/AppConnections/AppConnectionsPage/route' import { Route as sshLayoutImport } from './pages/ssh/layout' import { Route as secretScanningLayoutImport } from './pages/secret-scanning/layout' @@ -270,10 +270,6 @@ const AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingImport = createFileRoute( '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing', )() -const AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingImport = - createFileRoute( - '/_authenticate/_inject-org-details/_org-layout/organization/networking', - )() const AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsImport = createFileRoute( '/_authenticate/_inject-org-details/_org-layout/organization/app-connections', @@ -594,14 +590,6 @@ const AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute = AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute, } as any) -const AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingRoute = - AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingImport.update({ - id: '/networking', - path: '/networking', - getParentRoute: () => - AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute, - } as any) - const AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRoute = AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsImport.update({ id: '/app-connections', @@ -658,6 +646,14 @@ const organizationProjectsPageRouteRoute = AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute, } as any) +const organizationNetworkingPageRouteRoute = + organizationNetworkingPageRouteImport.update({ + id: '/networking', + path: '/networking', + getParentRoute: () => + AuthenticateInjectOrgDetailsOrgLayoutOrganizationRoute, + } as any) + const organizationBillingPageRouteRoute = organizationBillingPageRouteImport.update({ id: '/billing', @@ -807,14 +803,6 @@ const organizationSecretSharingPageRouteRoute = AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute, } as any) -const organizationNetworkingPageRouteRoute = - organizationNetworkingPageRouteImport.update({ - id: '/', - path: '/', - getParentRoute: () => - AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingRoute, - } as any) - const organizationAppConnectionsAppConnectionsPageRouteRoute = organizationAppConnectionsAppConnectionsPageRouteImport.update({ id: '/', @@ -2477,6 +2465,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof organizationBillingPageRouteImport parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport } + '/_authenticate/_inject-org-details/_org-layout/organization/networking': { + id: '/_authenticate/_inject-org-details/_org-layout/organization/networking' + path: '/networking' + fullPath: '/organization/networking' + preLoaderRoute: typeof organizationNetworkingPageRouteImport + parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport + } '/_authenticate/_inject-org-details/_org-layout/organization/projects': { id: '/_authenticate/_inject-org-details/_org-layout/organization/projects' path: '/projects' @@ -2533,13 +2528,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsImport parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport } - '/_authenticate/_inject-org-details/_org-layout/organization/networking': { - id: '/_authenticate/_inject-org-details/_org-layout/organization/networking' - path: '/networking' - fullPath: '/organization/networking' - preLoaderRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingImport - parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationImport - } '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing': { id: '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing' path: '/secret-sharing' @@ -2568,13 +2556,6 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof organizationAppConnectionsAppConnectionsPageRouteImport parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsImport } - '/_authenticate/_inject-org-details/_org-layout/organization/networking/': { - id: '/_authenticate/_inject-org-details/_org-layout/organization/networking/' - path: '/' - fullPath: '/organization/networking/' - preLoaderRoute: typeof organizationNetworkingPageRouteImport - parentRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingImport - } '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/': { id: '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/' path: '/' @@ -4002,20 +3983,6 @@ const AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithCh AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteChildren, ) -interface AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingRouteChildren { - organizationNetworkingPageRouteRoute: typeof organizationNetworkingPageRouteRoute -} - -const AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingRouteChildren: AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingRouteChildren = - { - organizationNetworkingPageRouteRoute: organizationNetworkingPageRouteRoute, - } - -const AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingRouteWithChildren = - AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingRoute._addFileChildren( - AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingRouteChildren, - ) - interface AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteChildren { organizationSecretSharingPageRouteRoute: typeof organizationSecretSharingPageRouteRoute organizationSecretSharingSettingsPageRouteRoute: typeof organizationSecretSharingSettingsPageRouteRoute @@ -4055,9 +4022,9 @@ interface AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren { organizationAccessManagementPageRouteRoute: typeof organizationAccessManagementPageRouteRoute organizationAuditLogsPageRouteRoute: typeof organizationAuditLogsPageRouteRoute organizationBillingPageRouteRoute: typeof organizationBillingPageRouteRoute + organizationNetworkingPageRouteRoute: typeof organizationNetworkingPageRouteRoute organizationProjectsPageRouteRoute: typeof organizationProjectsPageRouteRoute AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren - AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingRouteWithChildren AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRoute: typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRouteWithChildren organizationGroupDetailsByIDPageRouteRoute: typeof organizationGroupDetailsByIDPageRouteRoute @@ -4072,11 +4039,10 @@ const AuthenticateInjectOrgDetailsOrgLayoutOrganizationRouteChildren: Authentica organizationAccessManagementPageRouteRoute, organizationAuditLogsPageRouteRoute: organizationAuditLogsPageRouteRoute, organizationBillingPageRouteRoute: organizationBillingPageRouteRoute, + organizationNetworkingPageRouteRoute: organizationNetworkingPageRouteRoute, organizationProjectsPageRouteRoute: organizationProjectsPageRouteRoute, AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRoute: AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren, - AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingRoute: - AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingRouteWithChildren, AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRoute: AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren, AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRoute: @@ -5057,6 +5023,7 @@ export interface FileRoutesByFullPath { '/organization/access-management': typeof organizationAccessManagementPageRouteRoute '/organization/audit-logs': typeof organizationAuditLogsPageRouteRoute '/organization/billing': typeof organizationBillingPageRouteRoute + '/organization/networking': typeof organizationNetworkingPageRouteRoute '/organization/projects': typeof organizationProjectsPageRouteRoute '/admin/access-management': typeof adminAccessManagementPageRouteRoute '/admin/authentication': typeof adminAuthenticationPageRouteRoute @@ -5065,12 +5032,10 @@ export interface FileRoutesByFullPath { '/admin/environment': typeof adminEnvironmentPageRouteRoute '/admin/integrations': typeof adminIntegrationsPageRouteRoute '/organization/app-connections': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren - '/organization/networking': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingRouteWithChildren '/organization/secret-sharing': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren '/organization/settings': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRouteWithChildren '/secret-manager/$projectId': typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdRouteWithChildren '/organization/app-connections/': typeof organizationAppConnectionsAppConnectionsPageRouteRoute - '/organization/networking/': typeof organizationNetworkingPageRouteRoute '/organization/secret-sharing/': typeof organizationSecretSharingPageRouteRoute '/organization/settings/': typeof organizationSettingsPageRouteRoute '/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute @@ -5294,6 +5259,7 @@ export interface FileRoutesByTo { '/organization/access-management': typeof organizationAccessManagementPageRouteRoute '/organization/audit-logs': typeof organizationAuditLogsPageRouteRoute '/organization/billing': typeof organizationBillingPageRouteRoute + '/organization/networking': typeof organizationNetworkingPageRouteRoute '/organization/projects': typeof organizationProjectsPageRouteRoute '/admin/access-management': typeof adminAccessManagementPageRouteRoute '/admin/authentication': typeof adminAuthenticationPageRouteRoute @@ -5303,7 +5269,6 @@ export interface FileRoutesByTo { '/admin/integrations': typeof adminIntegrationsPageRouteRoute '/secret-manager/$projectId': typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdRouteWithChildren '/organization/app-connections': typeof organizationAppConnectionsAppConnectionsPageRouteRoute - '/organization/networking': typeof organizationNetworkingPageRouteRoute '/organization/secret-sharing': typeof organizationSecretSharingPageRouteRoute '/organization/settings': typeof organizationSettingsPageRouteRoute '/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute @@ -5529,6 +5494,7 @@ export interface FileRoutesById { '/_authenticate/_inject-org-details/_org-layout/organization/access-management': typeof organizationAccessManagementPageRouteRoute '/_authenticate/_inject-org-details/_org-layout/organization/audit-logs': typeof organizationAuditLogsPageRouteRoute '/_authenticate/_inject-org-details/_org-layout/organization/billing': typeof organizationBillingPageRouteRoute + '/_authenticate/_inject-org-details/_org-layout/organization/networking': typeof organizationNetworkingPageRouteRoute '/_authenticate/_inject-org-details/_org-layout/organization/projects': typeof organizationProjectsPageRouteRoute '/_authenticate/_inject-org-details/admin/_admin-layout/access-management': typeof adminAccessManagementPageRouteRoute '/_authenticate/_inject-org-details/admin/_admin-layout/authentication': typeof adminAuthenticationPageRouteRoute @@ -5537,12 +5503,10 @@ export interface FileRoutesById { '/_authenticate/_inject-org-details/admin/_admin-layout/environment': typeof adminEnvironmentPageRouteRoute '/_authenticate/_inject-org-details/admin/_admin-layout/integrations': typeof adminIntegrationsPageRouteRoute '/_authenticate/_inject-org-details/_org-layout/organization/app-connections': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationAppConnectionsRouteWithChildren - '/_authenticate/_inject-org-details/_org-layout/organization/networking': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationNetworkingRouteWithChildren '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSecretSharingRouteWithChildren '/_authenticate/_inject-org-details/_org-layout/organization/settings': typeof AuthenticateInjectOrgDetailsOrgLayoutOrganizationSettingsRouteWithChildren '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId': typeof AuthenticateInjectOrgDetailsOrgLayoutSecretManagerProjectIdRouteWithChildren '/_authenticate/_inject-org-details/_org-layout/organization/app-connections/': typeof organizationAppConnectionsAppConnectionsPageRouteRoute - '/_authenticate/_inject-org-details/_org-layout/organization/networking/': typeof organizationNetworkingPageRouteRoute '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/': typeof organizationSecretSharingPageRouteRoute '/_authenticate/_inject-org-details/_org-layout/organization/settings/': typeof organizationSettingsPageRouteRoute '/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId': typeof organizationGroupDetailsByIDPageRouteRoute @@ -5778,6 +5742,7 @@ export interface FileRouteTypes { | '/organization/access-management' | '/organization/audit-logs' | '/organization/billing' + | '/organization/networking' | '/organization/projects' | '/admin/access-management' | '/admin/authentication' @@ -5786,12 +5751,10 @@ export interface FileRouteTypes { | '/admin/environment' | '/admin/integrations' | '/organization/app-connections' - | '/organization/networking' | '/organization/secret-sharing' | '/organization/settings' | '/secret-manager/$projectId' | '/organization/app-connections/' - | '/organization/networking/' | '/organization/secret-sharing/' | '/organization/settings/' | '/organization/groups/$groupId' @@ -6014,6 +5977,7 @@ export interface FileRouteTypes { | '/organization/access-management' | '/organization/audit-logs' | '/organization/billing' + | '/organization/networking' | '/organization/projects' | '/admin/access-management' | '/admin/authentication' @@ -6023,7 +5987,6 @@ export interface FileRouteTypes { | '/admin/integrations' | '/secret-manager/$projectId' | '/organization/app-connections' - | '/organization/networking' | '/organization/secret-sharing' | '/organization/settings' | '/organization/groups/$groupId' @@ -6247,6 +6210,7 @@ export interface FileRouteTypes { | '/_authenticate/_inject-org-details/_org-layout/organization/access-management' | '/_authenticate/_inject-org-details/_org-layout/organization/audit-logs' | '/_authenticate/_inject-org-details/_org-layout/organization/billing' + | '/_authenticate/_inject-org-details/_org-layout/organization/networking' | '/_authenticate/_inject-org-details/_org-layout/organization/projects' | '/_authenticate/_inject-org-details/admin/_admin-layout/access-management' | '/_authenticate/_inject-org-details/admin/_admin-layout/authentication' @@ -6255,12 +6219,10 @@ export interface FileRouteTypes { | '/_authenticate/_inject-org-details/admin/_admin-layout/environment' | '/_authenticate/_inject-org-details/admin/_admin-layout/integrations' | '/_authenticate/_inject-org-details/_org-layout/organization/app-connections' - | '/_authenticate/_inject-org-details/_org-layout/organization/networking' | '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing' | '/_authenticate/_inject-org-details/_org-layout/organization/settings' | '/_authenticate/_inject-org-details/_org-layout/secret-manager/$projectId' | '/_authenticate/_inject-org-details/_org-layout/organization/app-connections/' - | '/_authenticate/_inject-org-details/_org-layout/organization/networking/' | '/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/' | '/_authenticate/_inject-org-details/_org-layout/organization/settings/' | '/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId' @@ -6703,9 +6665,9 @@ export const routeTree = rootRoute "/_authenticate/_inject-org-details/_org-layout/organization/access-management", "/_authenticate/_inject-org-details/_org-layout/organization/audit-logs", "/_authenticate/_inject-org-details/_org-layout/organization/billing", + "/_authenticate/_inject-org-details/_org-layout/organization/networking", "/_authenticate/_inject-org-details/_org-layout/organization/projects", "/_authenticate/_inject-org-details/_org-layout/organization/app-connections", - "/_authenticate/_inject-org-details/_org-layout/organization/networking", "/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing", "/_authenticate/_inject-org-details/_org-layout/organization/settings", "/_authenticate/_inject-org-details/_org-layout/organization/groups/$groupId", @@ -6744,6 +6706,10 @@ export const routeTree = rootRoute "filePath": "organization/BillingPage/route.tsx", "parent": "/_authenticate/_inject-org-details/_org-layout/organization" }, + "/_authenticate/_inject-org-details/_org-layout/organization/networking": { + "filePath": "organization/NetworkingPage/route.tsx", + "parent": "/_authenticate/_inject-org-details/_org-layout/organization" + }, "/_authenticate/_inject-org-details/_org-layout/organization/projects": { "filePath": "organization/ProjectsPage/route.tsx", "parent": "/_authenticate/_inject-org-details/_org-layout/organization" @@ -6780,13 +6746,6 @@ export const routeTree = rootRoute "/_authenticate/_inject-org-details/_org-layout/organization/app-connections/$appConnection/oauth/callback" ] }, - "/_authenticate/_inject-org-details/_org-layout/organization/networking": { - "filePath": "", - "parent": "/_authenticate/_inject-org-details/_org-layout/organization", - "children": [ - "/_authenticate/_inject-org-details/_org-layout/organization/networking/" - ] - }, "/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing": { "filePath": "", "parent": "/_authenticate/_inject-org-details/_org-layout/organization", @@ -6814,10 +6773,6 @@ export const routeTree = rootRoute "filePath": "organization/AppConnections/AppConnectionsPage/route.tsx", "parent": "/_authenticate/_inject-org-details/_org-layout/organization/app-connections" }, - "/_authenticate/_inject-org-details/_org-layout/organization/networking/": { - "filePath": "organization/NetworkingPage/route.tsx", - "parent": "/_authenticate/_inject-org-details/_org-layout/organization/networking" - }, "/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing/": { "filePath": "organization/SecretSharingPage/route.tsx", "parent": "/_authenticate/_inject-org-details/_org-layout/organization/secret-sharing" diff --git a/frontend/src/routes.ts b/frontend/src/routes.ts index bebc50339..e84e5873d 100644 --- a/frontend/src/routes.ts +++ b/frontend/src/routes.ts @@ -40,7 +40,7 @@ const organizationRoutes = route("/organization", [ "organization/AppConnections/OauthCallbackPage/route.tsx" ) ]), - route("/networking", [index("organization/NetworkingPage/route.tsx")]) + route("/networking", "organization/NetworkingPage/route.tsx") ]); const secretManagerRoutes = route("/projects/secret-management/$projectId", [ From 1e6beb08c945b7176a830039d5244466b25a4a52 Mon Sep 17 00:00:00 2001 From: x032205 Date: Fri, 17 Oct 2025 06:29:48 -0400 Subject: [PATCH 007/146] lint --- .../components/GatewayTab/GatewayTab.tsx | 2 +- .../GatewayTab/components/DeployGatewayModal.tsx | 16 +++++++++------- .../GatewayTab/components/DeployRelayModal.tsx | 11 ++++++----- .../NetworkingTabGroup/NetworkingTabGroup.tsx | 2 +- .../components/RelayTab/RelayTab.tsx | 1 + 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/GatewayTab.tsx b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/GatewayTab.tsx index d5e79d326..a93694a3d 100644 --- a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/GatewayTab.tsx +++ b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/GatewayTab.tsx @@ -48,8 +48,8 @@ import { usePopUp } from "@app/hooks"; import { gatewaysQueryKeys, useDeleteGatewayById } from "@app/hooks/api/gateways"; import { useDeleteGatewayV2ById } from "@app/hooks/api/gateways-v2"; -import { EditGatewayDetailsModal } from "./components/EditGatewayDetailsModal"; import { DeployGatewayModal } from "./components/DeployGatewayModal"; +import { EditGatewayDetailsModal } from "./components/EditGatewayDetailsModal"; const GatewayHealthStatus = ({ heartbeat }: { heartbeat?: string }) => { const heartbeatDate = heartbeat ? new Date(heartbeat) : null; diff --git a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployGatewayModal.tsx b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployGatewayModal.tsx index 2b8f17fe7..e5bc048c5 100644 --- a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployGatewayModal.tsx +++ b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployGatewayModal.tsx @@ -1,3 +1,10 @@ +import { useEffect, useMemo, useState } from "react"; +import { SingleValue } from "react-select"; +import { faCopy, faUpRightFromSquare } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useNavigate } from "@tanstack/react-router"; +import { twMerge } from "tailwind-merge"; + import { createNotification } from "@app/components/notifications"; import { FilterableSelect, @@ -7,6 +14,7 @@ import { Modal, ModalContent } from "@app/components/v2"; +import { ROUTE_PATHS } from "@app/const/routes"; import { useOrganization } from "@app/context"; import { useAddIdentityTokenAuth, @@ -16,14 +24,8 @@ import { } from "@app/hooks/api"; import { useGetRelays } from "@app/hooks/api/relays"; import { slugSchema } from "@app/lib/schemas"; -import { faCopy, faUpRightFromSquare } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { useEffect, useMemo, useState } from "react"; -import { SingleValue } from "react-select"; + import { RelayOption } from "./RelayOption"; -import { useNavigate } from "@tanstack/react-router"; -import { ROUTE_PATHS } from "@app/const/routes"; -import { twMerge } from "tailwind-merge"; type Props = { isOpen: boolean; diff --git a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployRelayModal.tsx b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployRelayModal.tsx index 2347c0472..399d9851c 100644 --- a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployRelayModal.tsx +++ b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployRelayModal.tsx @@ -1,3 +1,9 @@ +import { useEffect, useMemo, useState } from "react"; +import { SingleValue } from "react-select"; +import { faCopy, faUpRightFromSquare } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { twMerge } from "tailwind-merge"; + import { createNotification } from "@app/components/notifications"; import { FilterableSelect, @@ -15,11 +21,6 @@ import { useGetIdentityTokenAuth } from "@app/hooks/api"; import { slugSchema } from "@app/lib/schemas"; -import { faCopy, faUpRightFromSquare } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { useEffect, useMemo, useState } from "react"; -import { SingleValue } from "react-select"; -import { twMerge } from "tailwind-merge"; type Props = { isOpen: boolean; diff --git a/frontend/src/pages/organization/NetworkingPage/components/NetworkingTabGroup/NetworkingTabGroup.tsx b/frontend/src/pages/organization/NetworkingPage/components/NetworkingTabGroup/NetworkingTabGroup.tsx index dc90b7f21..07da157ab 100644 --- a/frontend/src/pages/organization/NetworkingPage/components/NetworkingTabGroup/NetworkingTabGroup.tsx +++ b/frontend/src/pages/organization/NetworkingPage/components/NetworkingTabGroup/NetworkingTabGroup.tsx @@ -1,10 +1,10 @@ import { useNavigate, useSearch } from "@tanstack/react-router"; import { Tab, TabList, TabPanel, Tabs } from "@app/components/v2"; +import { ROUTE_PATHS } from "@app/const/routes"; import { GatewayTab } from "../GatewayTab/GatewayTab"; import { RelayTab } from "../RelayTab/RelayTab"; -import { ROUTE_PATHS } from "@app/const/routes"; export const NetworkingTabGroup = () => { const navigate = useNavigate({ diff --git a/frontend/src/pages/organization/NetworkingPage/components/RelayTab/RelayTab.tsx b/frontend/src/pages/organization/NetworkingPage/components/RelayTab/RelayTab.tsx index 2bfa8b250..e731aab42 100644 --- a/frontend/src/pages/organization/NetworkingPage/components/RelayTab/RelayTab.tsx +++ b/frontend/src/pages/organization/NetworkingPage/components/RelayTab/RelayTab.tsx @@ -43,6 +43,7 @@ import { import { withPermission } from "@app/hoc"; import { usePopUp } from "@app/hooks"; import { useDeleteRelayById, useGetRelays } from "@app/hooks/api/relays"; + import { DeployRelayModal } from "../GatewayTab/components/DeployRelayModal"; const RelayHealthStatus = ({ heartbeat }: { heartbeat?: string }) => { From ab48e098d2c2df5ee65eee9a22615a4064d6ff2d Mon Sep 17 00:00:00 2001 From: x032205 Date: Fri, 17 Oct 2025 06:43:36 -0400 Subject: [PATCH 008/146] remove low opacity from input --- .../components/GatewayTab/components/DeployGatewayModal.tsx | 2 +- .../components/GatewayTab/components/DeployRelayModal.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployGatewayModal.tsx b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployGatewayModal.tsx index e5bc048c5..9a98ce4b1 100644 --- a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployGatewayModal.tsx +++ b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployGatewayModal.tsx @@ -211,7 +211,7 @@ export const DeployGatewayModal = ({ isOpen, onOpenChange }: Props) => {
- + {
- + Date: Fri, 17 Oct 2025 16:49:22 -0400 Subject: [PATCH 009/146] add "rotated
From ebb28844eed1adc852f68b6da79d892195e8e87d Mon Sep 17 00:00:00 2001 From: x032205 Date: Fri, 17 Oct 2025 22:54:22 -0400 Subject: [PATCH 010/146] make resource rotation account credentials write-only --- .../routes/v1/pam-resource-routers/index.ts | 4 +-- .../pam-resource-router.ts | 6 ++-- .../pam-resource/pam-resource-service.ts | 17 ++++++++-- .../postgres/postgres-resource-schemas.ts | 9 ++++++ .../components/PamAccountRow.tsx | 2 +- .../PamResourceForm/PostgresResourceForm.tsx | 32 ++++++++++++------- .../shared/SqlRotateAccountFields.tsx | 21 +++++++++--- 7 files changed, 65 insertions(+), 26 deletions(-) diff --git a/backend/src/ee/routes/v1/pam-resource-routers/index.ts b/backend/src/ee/routes/v1/pam-resource-routers/index.ts index a63b67d94..6b53781ae 100644 --- a/backend/src/ee/routes/v1/pam-resource-routers/index.ts +++ b/backend/src/ee/routes/v1/pam-resource-routers/index.ts @@ -1,7 +1,7 @@ import { PamResource } from "@app/ee/services/pam-resource/pam-resource-enums"; import { CreatePostgresResourceSchema, - PostgresResourceSchema, + SanitizedPostgresResourceSchema, UpdatePostgresResourceSchema } from "@app/ee/services/pam-resource/postgres/postgres-resource-schemas"; @@ -12,7 +12,7 @@ export const PAM_RESOURCE_REGISTER_ROUTER_MAP: Record { }), response: { 200: z.object({ - resources: ResourceSchema.array() + resources: SanitizedResourceSchema.array() }) } }, diff --git a/backend/src/ee/services/pam-resource/pam-resource-service.ts b/backend/src/ee/services/pam-resource/pam-resource-service.ts index 1c5ead252..076ec6855 100644 --- a/backend/src/ee/services/pam-resource/pam-resource-service.ts +++ b/backend/src/ee/services/pam-resource/pam-resource-service.ts @@ -10,7 +10,7 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service"; import { TGatewayV2ServiceFactory } from "../gateway-v2/gateway-v2-service"; import { TLicenseServiceFactory } from "../license/license-service"; -import { encryptAccountCredentials } from "../pam-account/pam-account-fns"; +import { decryptAccountCredentials, encryptAccountCredentials } from "../pam-account/pam-account-fns"; import { TPamResourceDALFactory } from "./pam-resource-dal"; import { PamResource } from "./pam-resource-enums"; import { PAM_RESOURCE_FACTORY_MAP } from "./pam-resource-factory"; @@ -192,8 +192,19 @@ export const pamResourceServiceFactory = ({ gatewayV2Service ); - const validatedRotationAccountCredentials = - await factory.validateAccountCredentials(rotationAccountCredentials); + // Logic to prevent overwriting unedited censored values + const finalCredentials = { ...rotationAccountCredentials }; + if (resource.encryptedRotationAccountCredentials && rotationAccountCredentials.password === "******") { + const decryptedCredentials = await decryptAccountCredentials({ + encryptedCredentials: resource.encryptedRotationAccountCredentials, + projectId: resource.projectId, + kmsService + }); + + finalCredentials.password = decryptedCredentials.password; + } + + const validatedRotationAccountCredentials = await factory.validateAccountCredentials(finalCredentials); updateDoc.encryptedRotationAccountCredentials = await encryptAccountCredentials({ credentials: validatedRotationAccountCredentials, diff --git a/backend/src/ee/services/pam-resource/postgres/postgres-resource-schemas.ts b/backend/src/ee/services/pam-resource/postgres/postgres-resource-schemas.ts index f383f521a..bbe83a3a4 100644 --- a/backend/src/ee/services/pam-resource/postgres/postgres-resource-schemas.ts +++ b/backend/src/ee/services/pam-resource/postgres/postgres-resource-schemas.ts @@ -26,6 +26,15 @@ export const PostgresResourceSchema = BasePostgresResourceSchema.extend({ rotationAccountCredentials: PostgresAccountCredentialsSchema.nullable().optional() }); +export const SanitizedPostgresResourceSchema = BasePostgresResourceSchema.extend({ + connectionDetails: PostgresResourceConnectionDetailsSchema, + rotationAccountCredentials: PostgresAccountCredentialsSchema.pick({ + username: true + }) + .nullable() + .optional() +}); + export const PostgresResourceListItemSchema = z.object({ name: z.literal("PostgreSQL"), resource: z.literal(PamResource.Postgres) diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountRow.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountRow.tsx index 758ef2c20..8e7507ac9 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountRow.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountRow.tsx @@ -11,8 +11,8 @@ import { faTrash } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { twMerge } from "tailwind-merge"; import { formatDistance } from "date-fns"; +import { twMerge } from "tailwind-merge"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx index c172bb561..427fff40b 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx @@ -31,17 +31,25 @@ export const PostgresResourceForm = ({ resource, onSubmit }: Props) => { const form = useForm({ resolver: zodResolver(formSchema), - defaultValues: resource ?? { - resourceType: PamResourceType.Postgres, - connectionDetails: { - host: "", - port: 5432, - database: "default", - sslEnabled: true, - sslRejectUnauthorized: true, - sslCertificate: undefined - } - } + defaultValues: resource + ? { + ...resource, + rotationAccountCredentials: { + ...resource.rotationAccountCredentials, + password: "******" + } + } + : { + resourceType: PamResourceType.Postgres, + connectionDetails: { + host: "", + port: 5432, + database: "default", + sslEnabled: true, + sslRejectUnauthorized: true, + sslCertificate: undefined + } + } }); const { @@ -62,7 +70,7 @@ export const PostgresResourceForm = ({ resource, onSubmit }: Props) => { selectedTabIndex={selectedTabIndex} setSelectedTabIndex={setSelectedTabIndex} /> - +
)} From 3a61ce07365fc6f5ec0dcda06c3ec6476c8b6dac Mon Sep 17 00:00:00 2001 From: Carlos Monastyrski Date: Mon, 20 Oct 2025 21:44:39 -0300 Subject: [PATCH 025/146] Lint fix --- .../components/SecretDropzone/SecretDropzone.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretDropzone/SecretDropzone.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretDropzone/SecretDropzone.tsx index 5d8ea59c3..ded34f9d4 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretDropzone/SecretDropzone.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretDropzone/SecretDropzone.tsx @@ -38,12 +38,12 @@ import { fetchProjectSecrets, mergePersonalSecrets } from "@app/hooks/api/secret import { SecretV3RawSanitized } from "@app/hooks/api/secrets/types"; import { - PopUpNames, - usePopUpAction, - useBatchModeActions, + BatchContext, PendingSecretCreate, PendingSecretUpdate, - BatchContext + PopUpNames, + useBatchModeActions, + usePopUpAction } from "../../SecretMainPage.store"; import { CopySecretsFromBoard } from "./CopySecretsFromBoard"; import { PasteSecretEnvModal } from "./PasteSecretEnvModal"; From 64b3d6132599bfa9a163f5f20f86a0cb42131b95 Mon Sep 17 00:00:00 2001 From: x032205 Date: Mon, 20 Oct 2025 20:45:54 -0400 Subject: [PATCH 026/146] tweak pam resource query --- frontend/src/hooks/api/pam/queries.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/hooks/api/pam/queries.tsx b/frontend/src/hooks/api/pam/queries.tsx index c6df40e37..60ead74ec 100644 --- a/frontend/src/hooks/api/pam/queries.tsx +++ b/frontend/src/hooks/api/pam/queries.tsx @@ -12,7 +12,7 @@ export const pamKeys = { session: () => [...pamKeys.all, "session"] as const, listResourceOptions: () => [...pamKeys.resource(), "options"] as const, listResources: (projectId: string) => [...pamKeys.resource(), "list", projectId], - getResource: (resourceId?: string) => [...pamKeys.resource(), "get", resourceId], + getResource: (resourceId: string) => [...pamKeys.resource(), "get", resourceId], listAccounts: (projectId: string) => [...pamKeys.account(), "list", projectId], getSession: (sessionId: string) => [...pamKeys.session(), "get", sessionId], listSessions: (projectId: string) => [...pamKeys.session(), "list", projectId] @@ -77,7 +77,7 @@ export const useGetPamResourceById = ( > ) => { return useQuery({ - queryKey: pamKeys.getResource(resourceId), + queryKey: pamKeys.getResource(resourceId || ""), queryFn: async () => { const { data } = await apiRequest.get<{ resource: TPamResource }>( `/api/v1/pam/resources/${resourceId}` From 2b6fcb2564d61a35fd76f7ce6d665f8f633942e1 Mon Sep 17 00:00:00 2001 From: x032205 Date: Mon, 20 Oct 2025 20:46:15 -0400 Subject: [PATCH 027/146] fix rotation account configured detection --- backend/src/ee/services/pam-resource/pam-resource-schemas.ts | 2 ++ .../components/PamAccountForm/PostgresAccountForm.tsx | 2 +- .../components/PamAccountForm/RotateAccountFields.tsx | 5 ++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/backend/src/ee/services/pam-resource/pam-resource-schemas.ts b/backend/src/ee/services/pam-resource/pam-resource-schemas.ts index 5b0199166..8f4752f4e 100644 --- a/backend/src/ee/services/pam-resource/pam-resource-schemas.ts +++ b/backend/src/ee/services/pam-resource/pam-resource-schemas.ts @@ -31,6 +31,8 @@ export const BasePamAccountSchemaWithResource = BasePamAccountSchema.extend({ id: true, name: true, resourceType: true + }).extend({ + rotationCredentialsConfigured: z.boolean() }) }); diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx index bbf7982fb..5a2104275 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx @@ -54,7 +54,7 @@ export const PostgresAccountForm = ({ account, resourceId, onSubmit }: Props) => } else { setRotationCredentialsConfigured(!!resource?.rotationAccountCredentials); } - }, [account]); + }, [account, resource]); return ( diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/RotateAccountFields.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/RotateAccountFields.tsx index 32a7040ec..2739e1cd5 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/RotateAccountFields.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/RotateAccountFields.tsx @@ -22,7 +22,10 @@ export const RotateAccountFields = ({ const rotationEnabled = watch("rotationEnabled"); return ( - +
Date: Mon, 20 Oct 2025 21:03:35 -0400 Subject: [PATCH 028/146] fix endpoint and improve frontend performance --- frontend/src/hooks/api/pam/queries.tsx | 8 +++++--- .../components/PamAccountForm/PamAccountForm.tsx | 8 +++++++- .../components/PamAccountForm/PostgresAccountForm.tsx | 9 ++++++--- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/frontend/src/hooks/api/pam/queries.tsx b/frontend/src/hooks/api/pam/queries.tsx index 60ead74ec..22810c4e3 100644 --- a/frontend/src/hooks/api/pam/queries.tsx +++ b/frontend/src/hooks/api/pam/queries.tsx @@ -4,6 +4,7 @@ import { apiRequest } from "@app/config/request"; import { TPamResourceOption } from "./types/resource-options"; import { TPamAccount, TPamFolder, TPamResource, TPamSession } from "./types"; +import { PamResourceType } from "./enums"; export const pamKeys = { all: ["pam"] as const, @@ -70,22 +71,23 @@ export const useListPamResources = ( }; export const useGetPamResourceById = ( + resourceType?: PamResourceType, resourceId?: string, options?: Omit< UseQueryOptions>, - "queryKey" | "queryFn" | "enabled" + "queryKey" | "queryFn" > ) => { return useQuery({ queryKey: pamKeys.getResource(resourceId || ""), queryFn: async () => { const { data } = await apiRequest.get<{ resource: TPamResource }>( - `/api/v1/pam/resources/${resourceId}` + `/api/v1/pam/resources/${resourceType}/${resourceId}` ); return data.resource; }, - enabled: !!resourceId, + enabled: !!resourceId && !!resourceType && (options?.enabled ?? true), ...options }); }; diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PamAccountForm.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PamAccountForm.tsx index eee101a54..8b553e656 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PamAccountForm.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PamAccountForm.tsx @@ -65,7 +65,13 @@ const CreateForm = ({ switch (resourceType) { case PamResourceType.Postgres: - return ; + return ( + + ); default: throw new Error(`Unhandled resource: ${resourceType}`); } diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx index 5a2104275..c353a278b 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx @@ -4,7 +4,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { Button, ModalClose } from "@app/components/v2"; -import { TPostgresAccount, useGetPamResourceById } from "@app/hooks/api/pam"; +import { PamResourceType, TPostgresAccount, useGetPamResourceById } from "@app/hooks/api/pam"; import { BaseSqlAccountSchema } from "./shared/sql-account-schemas"; import { SqlAccountFields } from "./shared/SqlAccountFields"; @@ -14,6 +14,7 @@ import { RotateAccountFields, rotateAccountFieldsSchema } from "./RotateAccountF type Props = { account?: TPostgresAccount; resourceId?: string; + resourceType?: PamResourceType; onSubmit: (formData: FormData) => Promise; }; @@ -23,7 +24,7 @@ const formSchema = genericAccountFieldsSchema.extend(rotateAccountFieldsSchema.s type FormData = z.infer; -export const PostgresAccountForm = ({ account, resourceId, onSubmit }: Props) => { +export const PostgresAccountForm = ({ account, resourceId, resourceType, onSubmit }: Props) => { const isUpdate = Boolean(account); const form = useForm({ @@ -46,7 +47,9 @@ export const PostgresAccountForm = ({ account, resourceId, onSubmit }: Props) => const [rotationCredentialsConfigured, setRotationCredentialsConfigured] = useState(false); - const { data: resource } = useGetPamResourceById(resourceId); + const { data: resource } = useGetPamResourceById(resourceType, resourceId, { + enabled: !account && !!resourceId && !!resourceType + }); useEffect(() => { if (account) { From bdbec5b1589320d705f5acf9ab7069b0daed0810 Mon Sep 17 00:00:00 2001 From: x032205 Date: Mon, 20 Oct 2025 21:09:01 -0400 Subject: [PATCH 029/146] add resource type to error log --- backend/src/ee/services/audit-log/audit-log-types.ts | 1 + backend/src/ee/services/pam-account/pam-account-service.ts | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/src/ee/services/audit-log/audit-log-types.ts b/backend/src/ee/services/audit-log/audit-log-types.ts index be5906af5..94561e6d8 100644 --- a/backend/src/ee/services/audit-log/audit-log-types.ts +++ b/backend/src/ee/services/audit-log/audit-log-types.ts @@ -3841,6 +3841,7 @@ interface PamAccountCredentialRotationFailedEvent { accountName: string; accountId: string; resourceId: string; + resourceType: string; errorMessage: string; }; } diff --git a/backend/src/ee/services/pam-account/pam-account-service.ts b/backend/src/ee/services/pam-account/pam-account-service.ts index 209eb25b9..4d0ccc6ab 100644 --- a/backend/src/ee/services/pam-account/pam-account-service.ts +++ b/backend/src/ee/services/pam-account/pam-account-service.ts @@ -554,9 +554,11 @@ export const pamAccountServiceFactory = ({ const batch = accounts.slice(i, i + ROTATION_CONCURRENCY_LIMIT); const rotationPromises = batch.map(async (account) => { + let logResourceType = "unknown"; try { const resource = await pamResourceDAL.findById(account.resourceId); if (!resource || !resource.encryptedRotationAccountCredentials) return; + logResourceType = resource.resourceType; const { connectionDetails, rotationAccountCredentials, gatewayId, resourceType } = await decryptResource( resource, @@ -604,7 +606,7 @@ export const pamAccountServiceFactory = ({ accountId: account.id, accountName: account.name, resourceId: resource.id, - resourceType: resource.resourceType + resourceType: logResourceType } } }); @@ -623,6 +625,7 @@ export const pamAccountServiceFactory = ({ accountId: account.id, accountName: account.name, resourceId: account.resourceId, + resourceType: logResourceType, errorMessage } } From efd63dcb35b85e7751dc9ba0daf09282d25729a1 Mon Sep 17 00:00:00 2001 From: x032205 Date: Mon, 20 Oct 2025 21:13:40 -0400 Subject: [PATCH 030/146] improve rotation account error response --- .../src/ee/services/pam-resource/pam-resource-service.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/backend/src/ee/services/pam-resource/pam-resource-service.ts b/backend/src/ee/services/pam-resource/pam-resource-service.ts index 683e0bca4..9ec702b24 100644 --- a/backend/src/ee/services/pam-resource/pam-resource-service.ts +++ b/backend/src/ee/services/pam-resource/pam-resource-service.ts @@ -213,12 +213,9 @@ export const pamResourceServiceFactory = ({ kmsService }); } catch (err) { - if ( - err instanceof BadRequestError && - err.message === "Account credentials invalid: Username or password incorrect" - ) { + if (err instanceof BadRequestError) { throw new BadRequestError({ - message: "Rotation Account credentials invalid: Username or password incorrect" + message: `Rotation Account Error: ${err.message}` }); } From 35d4720d8631288211a9a1a55c93b17464abf046 Mon Sep 17 00:00:00 2001 From: x032205 Date: Mon, 20 Oct 2025 21:24:57 -0400 Subject: [PATCH 031/146] final small fixes --- .../services/pam-account/pam-account-service.ts | 4 ++-- .../CustomProviderAuditLogStreamForm.tsx | 15 +++++++++------ .../PamAccountForm/shared/SqlAccountFields.tsx | 12 +++++++----- .../shared/SqlRotateAccountFields.tsx | 12 +++++++----- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/backend/src/ee/services/pam-account/pam-account-service.ts b/backend/src/ee/services/pam-account/pam-account-service.ts index 4d0ccc6ab..83e488231 100644 --- a/backend/src/ee/services/pam-account/pam-account-service.ts +++ b/backend/src/ee/services/pam-account/pam-account-service.ts @@ -611,6 +611,8 @@ export const pamAccountServiceFactory = ({ } }); } catch (error) { + logger.error(error, `Failed to rotate credentials for account [accountId=${account.id}]`); + const errorMessage = error instanceof Error ? error.message : "An unknown error occurred"; await auditLogService.createAuditLog({ @@ -630,8 +632,6 @@ export const pamAccountServiceFactory = ({ } } }); - - logger.error(error, `Failed to rotate credentials for account ${account.id}`); } }); diff --git a/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/CustomProviderAuditLogStreamForm.tsx b/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/CustomProviderAuditLogStreamForm.tsx index 7d2868dcc..b9a125900 100644 --- a/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/CustomProviderAuditLogStreamForm.tsx +++ b/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/CustomProviderAuditLogStreamForm.tsx @@ -7,6 +7,7 @@ import { z } from "zod"; import { Button, FormControl, FormLabel, IconButton, Input, ModalClose } from "@app/components/v2"; import { LogProvider } from "@app/hooks/api/auditLogStreams/enums"; import { TCustomProviderLogStream } from "@app/hooks/api/auditLogStreams/types/providers/custom-provider"; +import { useState } from "react"; type Props = { auditLogStream?: TCustomProviderLogStream; @@ -29,6 +30,8 @@ const formSchema = z.object({ type FormData = z.infer; export const CustomProviderAuditLogStreamForm = ({ auditLogStream, onSubmit }: Props) => { + const [showPassword, setShowPassword] = useState(false); + const isUpdate = Boolean(auditLogStream); const form = useForm({ @@ -96,10 +99,10 @@ export const CustomProviderAuditLogStreamForm = ({ auditLogStream, onSubmit }: P > { + placeholder="Bearer " + onFocus={() => { if ( auditLogStream && auditLogStream.credentials.headers[i] && @@ -108,9 +111,9 @@ export const CustomProviderAuditLogStreamForm = ({ auditLogStream, onSubmit }: P ) { field.onChange(""); } - e.target.type = "text"; + setShowPassword(true); }} - onBlur={(e) => { + onBlur={() => { if ( auditLogStream && auditLogStream.credentials.headers[i] && @@ -119,7 +122,7 @@ export const CustomProviderAuditLogStreamForm = ({ auditLogStream, onSubmit }: P ) { field.onChange("******"); } - e.target.type = "password"; + setShowPassword(false); }} /> diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/SqlAccountFields.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/SqlAccountFields.tsx index c32102231..3e9db178f 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/SqlAccountFields.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/SqlAccountFields.tsx @@ -1,9 +1,11 @@ import { Controller, useFormContext } from "react-hook-form"; import { FormControl, Input } from "@app/components/v2"; +import { useState } from "react"; export const SqlAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { const { control } = useFormContext(); + const [showPassword, setShowPassword] = useState(false); return (
@@ -33,19 +35,19 @@ export const SqlAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { > { + onFocus={() => { if (isUpdate && field.value === "******") { field.onChange(""); } - e.target.type = "text"; + setShowPassword(true); }} - onBlur={(e) => { + onBlur={() => { if (isUpdate && field.value === "") { field.onChange("******"); } - e.target.type = "password"; + setShowPassword(false); }} /> diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx index 05b28aa94..869594140 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx @@ -1,3 +1,4 @@ +import { useState } from "react"; import { Controller, useFormContext } from "react-hook-form"; import { @@ -11,6 +12,7 @@ import { export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { const { control } = useFormContext(); + const [showPassword, setShowPassword] = useState(false); return ( @@ -50,19 +52,19 @@ export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { > { + onFocus={() => { if (isUpdate && field.value === "******") { field.onChange(""); } - e.target.type = "text"; + setShowPassword(true); }} - onBlur={(e) => { + onBlur={() => { if (isUpdate && field.value === "") { field.onChange("******"); } - e.target.type = "password"; + setShowPassword(false); }} /> From 8bbddb09c0a1b47cde961325bd6fa8837cbd806e Mon Sep 17 00:00:00 2001 From: x032205 Date: Mon, 20 Oct 2025 21:28:27 -0400 Subject: [PATCH 032/146] lint --- frontend/src/hooks/api/pam/queries.tsx | 2 +- .../AuditLogStreamForm/CustomProviderAuditLogStreamForm.tsx | 2 +- .../components/PamAccountForm/shared/SqlAccountFields.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/hooks/api/pam/queries.tsx b/frontend/src/hooks/api/pam/queries.tsx index 22810c4e3..77afbe832 100644 --- a/frontend/src/hooks/api/pam/queries.tsx +++ b/frontend/src/hooks/api/pam/queries.tsx @@ -3,8 +3,8 @@ import { useQuery, UseQueryOptions } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; import { TPamResourceOption } from "./types/resource-options"; -import { TPamAccount, TPamFolder, TPamResource, TPamSession } from "./types"; import { PamResourceType } from "./enums"; +import { TPamAccount, TPamFolder, TPamResource, TPamSession } from "./types"; export const pamKeys = { all: ["pam"] as const, diff --git a/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/CustomProviderAuditLogStreamForm.tsx b/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/CustomProviderAuditLogStreamForm.tsx index b9a125900..e60f09c4a 100644 --- a/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/CustomProviderAuditLogStreamForm.tsx +++ b/frontend/src/pages/organization/SettingsPage/components/AuditLogStreamTab/AuditLogStreamForm/CustomProviderAuditLogStreamForm.tsx @@ -1,3 +1,4 @@ +import { useState } from "react"; import { Controller, FormProvider, useFieldArray, useForm } from "react-hook-form"; import { faPlus, faTrash } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -7,7 +8,6 @@ import { z } from "zod"; import { Button, FormControl, FormLabel, IconButton, Input, ModalClose } from "@app/components/v2"; import { LogProvider } from "@app/hooks/api/auditLogStreams/enums"; import { TCustomProviderLogStream } from "@app/hooks/api/auditLogStreams/types/providers/custom-provider"; -import { useState } from "react"; type Props = { auditLogStream?: TCustomProviderLogStream; diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/SqlAccountFields.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/SqlAccountFields.tsx index 3e9db178f..7d9e85c44 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/SqlAccountFields.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/SqlAccountFields.tsx @@ -1,7 +1,7 @@ +import { useState } from "react"; import { Controller, useFormContext } from "react-hook-form"; import { FormControl, Input } from "@app/components/v2"; -import { useState } from "react"; export const SqlAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { const { control } = useFormContext(); From df069cbd5b5037a4c4b0d01ed5c4dc612e816b57 Mon Sep 17 00:00:00 2001 From: x032205 Date: Mon, 20 Oct 2025 21:34:28 -0400 Subject: [PATCH 033/146] tiny greptile improvement --- frontend/src/hooks/api/pam/queries.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/src/hooks/api/pam/queries.tsx b/frontend/src/hooks/api/pam/queries.tsx index 77afbe832..6339b4761 100644 --- a/frontend/src/hooks/api/pam/queries.tsx +++ b/frontend/src/hooks/api/pam/queries.tsx @@ -13,7 +13,12 @@ export const pamKeys = { session: () => [...pamKeys.all, "session"] as const, listResourceOptions: () => [...pamKeys.resource(), "options"] as const, listResources: (projectId: string) => [...pamKeys.resource(), "list", projectId], - getResource: (resourceId: string) => [...pamKeys.resource(), "get", resourceId], + getResource: (resourceType: string, resourceId: string) => [ + ...pamKeys.resource(), + "get", + resourceType, + resourceId + ], listAccounts: (projectId: string) => [...pamKeys.account(), "list", projectId], getSession: (sessionId: string) => [...pamKeys.session(), "get", sessionId], listSessions: (projectId: string) => [...pamKeys.session(), "list", projectId] @@ -79,7 +84,7 @@ export const useGetPamResourceById = ( > ) => { return useQuery({ - queryKey: pamKeys.getResource(resourceId || ""), + queryKey: pamKeys.getResource(resourceType || "", resourceId || ""), queryFn: async () => { const { data } = await apiRequest.get<{ resource: TPamResource }>( `/api/v1/pam/resources/${resourceType}/${resourceId}` From c8a00e7e3fd6b0df3ad6f44a05a095a71b514b2f Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 21 Oct 2025 16:46:22 +0400 Subject: [PATCH 034/146] checkpoint --- backend/src/db/migrations/utils/env-config.ts | 15 +++++--- backend/src/db/migrations/utils/services.ts | 3 +- .../ee/services/license/license-service.ts | 38 ++++++++++--------- backend/src/lib/config/env.ts | 5 --- backend/src/server/routes/index.ts | 3 +- 5 files changed, 35 insertions(+), 29 deletions(-) diff --git a/backend/src/db/migrations/utils/env-config.ts b/backend/src/db/migrations/utils/env-config.ts index de32f4db9..6da7044aa 100644 --- a/backend/src/db/migrations/utils/env-config.ts +++ b/backend/src/db/migrations/utils/env-config.ts @@ -1,6 +1,7 @@ import { z } from "zod"; import { crypto } from "@app/lib/crypto/cryptography"; +import { removeTrailingSlash } from "@app/lib/fn"; import { zpStr } from "@app/lib/zod"; import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal"; @@ -22,13 +23,17 @@ const envSchema = z HSM_LIB_PATH: zpStr(z.string().optional()), HSM_PIN: zpStr(z.string().optional()), HSM_KEY_LABEL: zpStr(z.string().optional()), - HSM_SLOT: z.coerce.number().optional().default(0) + HSM_SLOT: z.coerce.number().optional().default(0), + + LICENSE_SERVER_URL: zpStr(z.string().optional().default("https://portal.infisical.com")), + LICENSE_SERVER_KEY: zpStr(z.string().optional()), + LICENSE_KEY: zpStr(z.string().optional()), + LICENSE_KEY_OFFLINE: zpStr(z.string().optional()), + INTERNAL_REGION: zpStr(z.enum(["us", "eu"]).optional()), + + SITE_URL: zpStr(z.string().transform((val) => (val ? removeTrailingSlash(val) : val))).optional() }) // To ensure that basic encryption is always possible. - .refine( - (data) => Boolean(data.ENCRYPTION_KEY) || Boolean(data.ROOT_ENCRYPTION_KEY), - "Either ENCRYPTION_KEY or ROOT_ENCRYPTION_KEY must be defined." - ) .transform((data) => ({ ...data, isHsmConfigured: diff --git a/backend/src/db/migrations/utils/services.ts b/backend/src/db/migrations/utils/services.ts index 1d61086fd..26640e38e 100644 --- a/backend/src/db/migrations/utils/services.ts +++ b/backend/src/db/migrations/utils/services.ts @@ -61,7 +61,8 @@ export const getMigrationEncryptionServices = async ({ envConfig, db, keyStore } licenseDAL, keyStore, identityOrgMembershipDAL, - projectDAL + projectDAL, + envConfig }); // ----- HSM startup ----- diff --git a/backend/src/ee/services/license/license-service.ts b/backend/src/ee/services/license/license-service.ts index c2e67908f..3a5928713 100644 --- a/backend/src/ee/services/license/license-service.ts +++ b/backend/src/ee/services/license/license-service.ts @@ -10,7 +10,7 @@ import { CronJob } from "cron"; import { Knex } from "knex"; import { TKeyStoreFactory } from "@app/keystore/keystore"; -import { getConfig } from "@app/lib/config/env"; +import { TEnvConfig } from "@app/lib/config/env"; import { verifyOfflineLicense } from "@app/lib/crypto"; import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { logger } from "@app/lib/logger"; @@ -45,6 +45,10 @@ import { } from "./license-types"; type TLicenseServiceFactoryDep = { + envConfig: Pick< + TEnvConfig, + "LICENSE_SERVER_URL" | "LICENSE_SERVER_KEY" | "LICENSE_KEY" | "LICENSE_KEY_OFFLINE" | "INTERNAL_REGION" | "SITE_URL" + >; orgDAL: Pick; permissionService: Pick; licenseDAL: TLicenseDALFactory; @@ -67,26 +71,26 @@ export const licenseServiceFactory = ({ licenseDAL, keyStore, identityOrgMembershipDAL, - projectDAL + projectDAL, + envConfig }: TLicenseServiceFactoryDep) => { let isValidLicense = false; let instanceType = InstanceType.OnPrem; let onPremFeatures: TFeatureSet = getDefaultOnPremFeatures(); let selfHostedLicense: TOfflineLicense | null = null; - const appCfg = getConfig(); const licenseServerCloudApi = setupLicenseRequestWithStore( - appCfg.LICENSE_SERVER_URL || "", + envConfig.LICENSE_SERVER_URL || "", LICENSE_SERVER_CLOUD_LOGIN, - appCfg.LICENSE_SERVER_KEY || "", - appCfg.INTERNAL_REGION + envConfig.LICENSE_SERVER_KEY || "", + envConfig.INTERNAL_REGION ); const licenseServerOnPremApi = setupLicenseRequestWithStore( - appCfg.LICENSE_SERVER_URL || "", + envConfig.LICENSE_SERVER_URL || "", LICENSE_SERVER_ON_PREM_LOGIN, - appCfg.LICENSE_KEY || "", - appCfg.INTERNAL_REGION + envConfig.LICENSE_KEY || "", + envConfig.INTERNAL_REGION ); const syncLicenseKeyOnPremFeatures = async (shouldThrow: boolean = false) => { @@ -120,7 +124,7 @@ export const licenseServiceFactory = ({ const init = async () => { try { - if (appCfg.LICENSE_SERVER_KEY) { + if (envConfig.LICENSE_SERVER_KEY) { const token = await licenseServerCloudApi.refreshLicense(); if (token) instanceType = InstanceType.Cloud; logger.info(`Instance type: ${InstanceType.Cloud}`); @@ -128,7 +132,7 @@ export const licenseServiceFactory = ({ return; } - if (appCfg.LICENSE_KEY) { + if (envConfig.LICENSE_KEY) { const token = await licenseServerOnPremApi.refreshLicense(); if (token) { await syncLicenseKeyOnPremFeatures(true); @@ -139,10 +143,10 @@ export const licenseServiceFactory = ({ return; } - if (appCfg.LICENSE_KEY_OFFLINE) { + if (envConfig.LICENSE_KEY_OFFLINE) { let isValidOfflineLicense = true; const contents: TOfflineLicenseContents = JSON.parse( - Buffer.from(appCfg.LICENSE_KEY_OFFLINE, "base64").toString("utf8") + Buffer.from(envConfig.LICENSE_KEY_OFFLINE, "base64").toString("utf8") ); const isVerified = await verifyOfflineLicense(JSON.stringify(contents.license), contents.signature); @@ -181,7 +185,7 @@ export const licenseServiceFactory = ({ }; const initializeBackgroundSync = async () => { - if (appCfg.LICENSE_KEY) { + if (envConfig.LICENSE_KEY) { logger.info("Setting up background sync process for refresh onPremFeatures"); const job = new CronJob("*/10 * * * *", syncLicenseKeyOnPremFeatures); job.start(); @@ -397,8 +401,8 @@ export const licenseServiceFactory = ({ } = await licenseServerCloudApi.request.post( `/api/license-server/v1/customers/${organization.customerId}/billing-details/payment-methods`, { - success_url: `${appCfg.SITE_URL}/organization/billing`, - cancel_url: `${appCfg.SITE_URL}/organization/billing` + success_url: `${envConfig.SITE_URL}/organization/billing`, + cancel_url: `${envConfig.SITE_URL}/organization/billing` } ); @@ -411,7 +415,7 @@ export const licenseServiceFactory = ({ } = await licenseServerCloudApi.request.post( `/api/license-server/v1/customers/${organization.customerId}/billing-details/billing-portal`, { - return_url: `${appCfg.SITE_URL}/organization/billing` + return_url: `${envConfig.SITE_URL}/organization/billing` } ); diff --git a/backend/src/lib/config/env.ts b/backend/src/lib/config/env.ts index 15f878323..31e0eaeb4 100644 --- a/backend/src/lib/config/env.ts +++ b/backend/src/lib/config/env.ts @@ -363,11 +363,6 @@ const envSchema = z /* INTERNAL ----------------------------------------------------------------------------- */ INTERNAL_REGION: zpStr(z.enum(["us", "eu"]).optional()) }) - // To ensure that basic encryption is always possible. - .refine( - (data) => Boolean(data.ENCRYPTION_KEY) || Boolean(data.ROOT_ENCRYPTION_KEY), - "Either ENCRYPTION_KEY or ROOT_ENCRYPTION_KEY must be defined." - ) .refine( (data) => Boolean(data.REDIS_URL) || Boolean(data.REDIS_SENTINEL_HOSTS) || Boolean(data.REDIS_CLUSTER_HOSTS), "Either REDIS_URL, REDIS_SENTINEL_HOSTS or REDIS_CLUSTER_HOSTS must be defined." diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index eb94afd4f..bee447c36 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -559,7 +559,8 @@ export const registerRoutes = async ( licenseDAL, keyStore, identityOrgMembershipDAL, - projectDAL + projectDAL, + envConfig }); const tokenService = tokenServiceFactory({ tokenDAL: authTokenDAL, userDAL, membershipUserDAL }); From 0f925cfaad3f835272ade12fe7fcd3e2a561e565 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 21 Oct 2025 20:48:47 +0400 Subject: [PATCH 035/146] smaller fixes --- backend/src/db/migrations/utils/services.ts | 2 +- backend/src/ee/services/hsm/hsm-fns.ts | 3 ++- backend/src/ee/services/hsm/hsm-service.ts | 15 ++++++++++++++- backend/src/services/kms/kms-service.ts | 4 ++-- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/backend/src/db/migrations/utils/services.ts b/backend/src/db/migrations/utils/services.ts index 26640e38e..e4b675f7e 100644 --- a/backend/src/db/migrations/utils/services.ts +++ b/backend/src/db/migrations/utils/services.ts @@ -68,13 +68,13 @@ export const getMigrationEncryptionServices = async ({ envConfig, db, keyStore } // ----- HSM startup ----- const hsmModule = initializeHsmModule(envConfig); + hsmModule.initialize(); const hsmService = hsmServiceFactory({ hsmModule: hsmModule.getModule(), envConfig }); - hsmModule.initialize(); await hsmService.startService(); const hsmStatus = await isHsmActiveAndEnabled({ diff --git a/backend/src/ee/services/hsm/hsm-fns.ts b/backend/src/ee/services/hsm/hsm-fns.ts index 352a36443..2603f80bd 100644 --- a/backend/src/ee/services/hsm/hsm-fns.ts +++ b/backend/src/ee/services/hsm/hsm-fns.ts @@ -35,6 +35,7 @@ export const initializeHsmModule = (envConfig: Pick null); - rootKmsConfigEncryptionStrategy = rootKmsConfig?.encryptionStrategy as RootKeyEncryptionStrategy | null; + rootKmsConfigEncryptionStrategy = (rootKmsConfig?.encryptionStrategy || null) as RootKeyEncryptionStrategy | null; if (rootKmsConfigEncryptionStrategy === RootKeyEncryptionStrategy.HSM && !licenseService.onPremFeatures.hsm) { throw new BadRequestError({ message: "Your license does not include HSM integration. Please upgrade to the Enterprise plan to use HSM." diff --git a/backend/src/ee/services/hsm/hsm-service.ts b/backend/src/ee/services/hsm/hsm-service.ts index 0ed4c5faf..3b332e446 100644 --- a/backend/src/ee/services/hsm/hsm-service.ts +++ b/backend/src/ee/services/hsm/hsm-service.ts @@ -460,10 +460,23 @@ export const hsmServiceFactory = ({ hsmModule: { isInitialized, pkcs11 }, envCon } }; + const randomBytes = async (length: number) => { + if (!pkcs11 || !isInitialized) { + throw new Error("PKCS#11 module is not initialized"); + } + + const randomData = await $withSession((sessionHandle) => + pkcs11.C_GenerateRandom(sessionHandle, Buffer.alloc(length)) + ); + + return randomData; + }; + return { encrypt, startService, isActive, - decrypt + decrypt, + randomBytes }; }; diff --git a/backend/src/services/kms/kms-service.ts b/backend/src/services/kms/kms-service.ts index 035b3db02..5b35f2f63 100644 --- a/backend/src/services/kms/kms-service.ts +++ b/backend/src/services/kms/kms-service.ts @@ -1083,8 +1083,8 @@ export const kmsServiceFactory = ({ const isHsmActive = hsmStatus.isHsmConfigured; - logger.info("KMS: Generating new ROOT Key"); - const newRootKey = crypto.randomBytes(32); + logger.info(`KMS: Generating new ROOT Key with ${isHsmActive ? "HSM" : "software"} encryption`); + const newRootKey = isHsmActive ? await hsmService.randomBytes(32) : crypto.randomBytes(32); const encryptionStrategy = isHsmActive ? RootKeyEncryptionStrategy.HSM : RootKeyEncryptionStrategy.Software; From aa8aff9d8b998da52206393a22c51da0837642e7 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 21 Oct 2025 22:01:43 +0400 Subject: [PATCH 036/146] fix: persist softhsm configuration --- backend/Dockerfile.dev | 7 ++++--- backend/Dockerfile.dev.fips | 7 ++++--- backend/dev-entrypoint.sh | 16 ++++++++++++++++ docker-compose.dev.yml | 3 +++ 4 files changed, 27 insertions(+), 6 deletions(-) create mode 100755 backend/dev-entrypoint.sh diff --git a/backend/Dockerfile.dev b/backend/Dockerfile.dev index 5e17cf2bb..b5f4f7ac2 100644 --- a/backend/Dockerfile.dev +++ b/backend/Dockerfile.dev @@ -49,9 +49,6 @@ RUN rm -fr ${SOFTHSM2_SOURCES} # Install pkcs11-tool RUN apt-get install -y opensc -RUN mkdir -p /etc/softhsm2/tokens && \ - softhsm2-util --init-token --slot 0 --label "auth-app" --pin 1234 --so-pin 0000 - # ? App setup # Install Infisical CLI @@ -64,10 +61,14 @@ WORKDIR /app COPY package.json package.json COPY package-lock.json package-lock.json +COPY dev-entrypoint.sh dev-entrypoint.sh +RUN chmod +x dev-entrypoint.sh + RUN npm install COPY . . ENV HOST=0.0.0.0 +ENTRYPOINT ["/app/dev-entrypoint.sh"] CMD ["npm", "run", "dev:docker"] diff --git a/backend/Dockerfile.dev.fips b/backend/Dockerfile.dev.fips index db5107985..4d5b84260 100644 --- a/backend/Dockerfile.dev.fips +++ b/backend/Dockerfile.dev.fips @@ -50,9 +50,6 @@ RUN rm -fr ${SOFTHSM2_SOURCES} # Install pkcs11-tool RUN apt-get install -y opensc -RUN mkdir -p /etc/softhsm2/tokens && \ - softhsm2-util --init-token --slot 0 --label "auth-app" --pin 1234 --so-pin 0000 - WORKDIR /openssl-build RUN wget https://www.openssl.org/source/openssl-3.1.2.tar.gz \ && tar -xf openssl-3.1.2.tar.gz \ @@ -77,6 +74,9 @@ WORKDIR /app COPY package.json package.json COPY package-lock.json package-lock.json +COPY dev-entrypoint.sh dev-entrypoint.sh +RUN chmod +x dev-entrypoint.sh + RUN npm install COPY . . @@ -87,4 +87,5 @@ ENV OPENSSL_MODULES=/usr/local/lib/ossl-modules # ENV NODE_OPTIONS=--force-fips # Note(Daniel): We can't set this on the node options because it may break for existing folks using the infisical/infisical-fips image. Instead we call crypto.setFips(true) at runtime. ENV FIPS_ENABLED=true +ENTRYPOINT ["/app/dev-entrypoint.sh"] CMD ["npm", "run", "dev:docker"] diff --git a/backend/dev-entrypoint.sh b/backend/dev-entrypoint.sh new file mode 100755 index 000000000..9cb3c0a5e --- /dev/null +++ b/backend/dev-entrypoint.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +update-ca-certificates + +# Initialize SoftHSM token if it doesn't exist +if [ ! -f /etc/softhsm2/tokens/auth-app.db ]; then + echo "Initializing SoftHSM token..." + mkdir -p /etc/softhsm2/tokens + softhsm2-util --init-token --slot 0 --label "auth-app" --pin 1234 --so-pin 0000 + echo "SoftHSM token initialized" +else + echo "SoftHSM token already exists, skipping initialization" +fi + + +exec "$@" \ No newline at end of file diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 00dc19a46..e60ef1ba5 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -77,6 +77,7 @@ services: - TELEMETRY_ENABLED=false volumes: - ./backend/src:/app/src + - softhsm_tokens:/etc/softhsm2/tokens # SoftHSM tokens are stored in a volume to persist across container restarts extra_hosts: - "host.docker.internal:host-gateway" @@ -198,3 +199,5 @@ volumes: ldap_data: ldap_config: grafana_storage: + softhsm_tokens: + driver: local \ No newline at end of file From 4dd343af11206c9b32ad2b9da84704072fa559cf Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Tue, 21 Oct 2025 22:27:20 +0400 Subject: [PATCH 037/146] removed reloader requested changes --- .github/values.yaml | 57 ------------------- .../workflows/helm-release-infisical-core.yml | 2 +- ...rt-tests-infisical-standalone-postgres.yml | 2 +- .../CHANGELOG.md | 4 +- .../infisical-standalone-postgres/Chart.lock | 7 +-- .../infisical-standalone-postgres/Chart.yaml | 4 -- .../infisical-standalone-postgres/README.md | 1 - .../templates/infisical.yaml | 13 ----- .../templates/schema-migration-job.yaml | 56 ------------------ .../infisical-standalone-postgres/values.yaml | 8 +-- 10 files changed, 8 insertions(+), 146 deletions(-) delete mode 100644 .github/values.yaml delete mode 100644 helm-charts/infisical-standalone-postgres/templates/schema-migration-job.yaml diff --git a/.github/values.yaml b/.github/values.yaml deleted file mode 100644 index 1b3ffd87a..000000000 --- a/.github/values.yaml +++ /dev/null @@ -1,57 +0,0 @@ -## @section Common parameters -## - -## @param nameOverride Override release name -## -nameOverride: "" -## @param fullnameOverride Override release fullname -## -fullnameOverride: "" - -## @section Infisical backend parameters -## Documentation : https://infisical.com/docs/self-hosting/deployments/kubernetes -## - -infisical: - autoDatabaseSchemaMigration: false - - enabled: false - - name: infisical - replicaCount: 3 - image: - repository: infisical/staging_infisical - tag: "latest" - pullPolicy: Always - - deploymentAnnotations: - secrets.infisical.com/auto-reload: "true" - - kubeSecretRef: "managed-secret" - -ingress: - ## @param ingress.enabled Enable ingress - ## - enabled: true - ## @param ingress.ingressClassName Ingress class name - ## - ingressClassName: nginx - ## @param ingress.nginx.enabled Ingress controller - ## - # nginx: - # enabled: true - ## @param ingress.annotations Ingress annotations - ## - annotations: - cert-manager.io/cluster-issuer: "letsencrypt-prod" - hostName: "gamma.infisical.com" - tls: - - secretName: letsencrypt-prod - hosts: - - gamma.infisical.com - -postgresql: - enabled: false - -redis: - enabled: false diff --git a/.github/workflows/helm-release-infisical-core.yml b/.github/workflows/helm-release-infisical-core.yml index 6c317cc27..49118a5ae 100644 --- a/.github/workflows/helm-release-infisical-core.yml +++ b/.github/workflows/helm-release-infisical-core.yml @@ -56,7 +56,7 @@ jobs: --config ct.yaml \ --charts helm-charts/infisical-standalone-postgres \ --helm-extra-args="--timeout=300s" \ - --helm-extra-set-args="--set ingress.nginx.enabled=false --set infisical.autoDatabaseSchemaMigration=false --set infisical.replicaCount=1 --set infisical.image.tag=v0.132.2-postgres" \ + --helm-extra-set-args="--set ingress.nginx.enabled=false --set infisical.replicaCount=1 --set infisical.image.tag=v0.151.0" \ --namespace infisical-standalone-postgres release: diff --git a/.github/workflows/run-helm-chart-tests-infisical-standalone-postgres.yml b/.github/workflows/run-helm-chart-tests-infisical-standalone-postgres.yml index a7bb2c619..2023de187 100644 --- a/.github/workflows/run-helm-chart-tests-infisical-standalone-postgres.yml +++ b/.github/workflows/run-helm-chart-tests-infisical-standalone-postgres.yml @@ -67,5 +67,5 @@ jobs: --config ct.yaml \ --charts helm-charts/infisical-standalone-postgres \ --helm-extra-args="--timeout=300s" \ - --helm-extra-set-args="--set ingress.nginx.enabled=false --set infisical.autoDatabaseSchemaMigration=false --set infisical.replicaCount=1 --set infisical.image.tag=v0.132.2-postgres --set infisical.autoBootstrap.enabled=true" \ + --helm-extra-set-args="--set ingress.nginx.enabled=false --set infisical.replicaCount=1 --set infisical.image.tag=v0.151.0 --set infisical.autoBootstrap.enabled=true" \ --namespace infisical-standalone-postgres diff --git a/helm-charts/infisical-standalone-postgres/CHANGELOG.md b/helm-charts/infisical-standalone-postgres/CHANGELOG.md index a0e7216e0..5298432d7 100644 --- a/helm-charts/infisical-standalone-postgres/CHANGELOG.md +++ b/helm-charts/infisical-standalone-postgres/CHANGELOG.md @@ -1,7 +1,9 @@ ## 1.7.2 (October 20, 2025) Changes: +* Updated the default `infisical.image.tag` value to `v0.151.0`. +* `autoDatabaseSchemaMigration` has been fully removed as all newer versions of Infisical automatically run migrations as apart of the startup process. * Added automatic reloading support for the Infisical deployment when the `infisical.kubeSecretRef` kubernetes secret changes. - * Configurable by `infisical.redeployOnSecretChange: true|false`. Defaults to `true`. + * Configurable by `infisical.redeployOnSecretChange: true|false`. Defaults to `false`. ## 1.7.1 (October 10, 2025) diff --git a/helm-charts/infisical-standalone-postgres/Chart.lock b/helm-charts/infisical-standalone-postgres/Chart.lock index 8e7a3004e..b8ae1fd3f 100644 --- a/helm-charts/infisical-standalone-postgres/Chart.lock +++ b/helm-charts/infisical-standalone-postgres/Chart.lock @@ -8,8 +8,5 @@ dependencies: - name: redis repository: oci://registry-1.docker.io/bitnamicharts version: 18.14.1 -- name: reloader - repository: https://stakater.github.io/stakater-charts - version: 2.2.3 -digest: sha256:ae7d9ff526de87e972fed0f9c8f32ca40af8cf8b24b59d814cf72beb66ee4198 -generated: "2025-10-20T21:07:19.162271+04:00" +digest: sha256:57a18fb5258fc153d27b633f6570104c7628af651f08f3ae7e1cf8920c2c31fa +generated: "2025-10-21T22:30:21.313884+04:00" diff --git a/helm-charts/infisical-standalone-postgres/Chart.yaml b/helm-charts/infisical-standalone-postgres/Chart.yaml index 0d4381e72..21f358626 100644 --- a/helm-charts/infisical-standalone-postgres/Chart.yaml +++ b/helm-charts/infisical-standalone-postgres/Chart.yaml @@ -28,7 +28,3 @@ dependencies: version: 18.14.1 repository: oci://registry-1.docker.io/bitnamicharts condition: redis.enabled - - name: reloader - version: 2.2.3 - repository: https://stakater.github.io/stakater-charts - condition: infisical.redeployOnSecretChange diff --git a/helm-charts/infisical-standalone-postgres/README.md b/helm-charts/infisical-standalone-postgres/README.md index cd0e18848..b266563e8 100644 --- a/helm-charts/infisical-standalone-postgres/README.md +++ b/helm-charts/infisical-standalone-postgres/README.md @@ -18,7 +18,6 @@ A helm chart to deploy Infisical |-----|------|---------|-------------| | fullnameOverride | string | `""` | Overrides the full name of the release, affecting resource names | | infisical.affinity | object | `{}` | Node affinity settings for pod placement | -| infisical.autoDatabaseSchemaMigration | bool | `true` | Automatically migrates new database schema when deploying | | infisical.databaseSchemaMigrationJob.image.pullPolicy | string | `"IfNotPresent"` | Pulls image only if not present on the node | | infisical.databaseSchemaMigrationJob.image.repository | string | `"ghcr.io/groundnuty/k8s-wait-for"` | Image repository for migration wait job | | infisical.databaseSchemaMigrationJob.image.tag | string | `"no-root-v2.0"` | Image tag version | diff --git a/helm-charts/infisical-standalone-postgres/templates/infisical.yaml b/helm-charts/infisical-standalone-postgres/templates/infisical.yaml index d4637866b..d13c51295 100644 --- a/helm-charts/infisical-standalone-postgres/templates/infisical.yaml +++ b/helm-charts/infisical-standalone-postgres/templates/infisical.yaml @@ -4,9 +4,6 @@ kind: Deployment metadata: name: {{ include "infisical.fullname" . }} annotations: - {{- if $infisicalValues.redeployOnSecretChange }} - secret.reloader.stakater.com/reload: {{ $infisicalValues.kubeSecretRef }} - {{- end }} updatedAt: {{ now | date "2006-01-01 MST 15:04:05" | quote }} {{- with $infisicalValues.deploymentAnnotations }} {{- toYaml . | nindent 4 }} @@ -47,16 +44,6 @@ spec: {{- if $infisicalValues.image.imagePullSecrets }} imagePullSecrets: {{- toYaml $infisicalValues.image.imagePullSecrets | nindent 6 }} - {{- end }} - {{- if $infisicalValues.autoDatabaseSchemaMigration }} - serviceAccountName: {{ include "infisical.serviceAccountName" . }} - initContainers: - - name: "migration-init" - image: "{{ $infisicalValues.databaseSchemaMigrationJob.image.repository }}:{{ $infisicalValues.databaseSchemaMigrationJob.image.tag }}" - imagePullPolicy: {{ $infisicalValues.databaseSchemaMigrationJob.image.pullPolicy }} - args: - - "job" - - "{{ .Release.Name }}-schema-migration-{{ .Release.Revision }}" {{- end }} containers: - name: {{ template "infisical.name" . }}-{{ $infisicalValues.name }} diff --git a/helm-charts/infisical-standalone-postgres/templates/schema-migration-job.yaml b/helm-charts/infisical-standalone-postgres/templates/schema-migration-job.yaml deleted file mode 100644 index c53c6e3d1..000000000 --- a/helm-charts/infisical-standalone-postgres/templates/schema-migration-job.yaml +++ /dev/null @@ -1,56 +0,0 @@ -{{- $infisicalValues := .Values.infisical }} -{{- if $infisicalValues.autoDatabaseSchemaMigration }} -apiVersion: batch/v1 -kind: Job -metadata: - name: "{{ .Release.Name }}-schema-migration-{{ .Release.Revision }}" - labels: - helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" -spec: - backoffLimit: 10 - template: - metadata: - name: "{{ .Release.Name }}-create-tables" - labels: - app.kubernetes.io/managed-by: {{ .Release.Service | quote }} - app.kubernetes.io/instance: {{ .Release.Name | quote }} - helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" - {{- if $infisicalValues.redeployOnSecretChange }} - annotations: - secret.reloader.stakater.com/reload: {{ $infisicalValues.kubeSecretRef }} - {{- end }} - spec: - serviceAccountName: {{ include "infisical.serviceAccountName" . }} - {{- if $infisicalValues.image.imagePullSecrets }} - imagePullSecrets: - {{- toYaml $infisicalValues.image.imagePullSecrets | nindent 6 }} - {{- end }} - restartPolicy: OnFailure - containers: - - name: infisical-schema-migration - image: "{{ $infisicalValues.image.repository }}:{{ $infisicalValues.image.tag }}" - command: ["npm", "run", "migration:latest"] - env: - {{- if .Values.postgresql.useExistingPostgresSecret.enabled }} - - name: DB_CONNECTION_URI - valueFrom: - secretKeyRef: - name: {{ .Values.postgresql.useExistingPostgresSecret.existingConnectionStringSecret.name }} - key: {{ .Values.postgresql.useExistingPostgresSecret.existingConnectionStringSecret.key }} - {{- end }} - {{- if .Values.postgresql.enabled }} - - name: DB_CONNECTION_URI - value: {{ include "infisical.postgresDBConnectionString" . }} - {{- end }} - envFrom: - - secretRef: - name: {{ $infisicalValues.kubeSecretRef }} - {{- with $infisicalValues.extraVolumeMounts }} - volumeMounts: - {{- toYaml . | nindent 10 }} - {{- end }} - {{- with $infisicalValues.extraVolumes }} - volumes: - {{- toYaml . | nindent 8 }} - {{- end }} -{{- end }} \ No newline at end of file diff --git a/helm-charts/infisical-standalone-postgres/values.yaml b/helm-charts/infisical-standalone-postgres/values.yaml index 202a9008a..e0a81d9e3 100644 --- a/helm-charts/infisical-standalone-postgres/values.yaml +++ b/helm-charts/infisical-standalone-postgres/values.yaml @@ -10,12 +10,6 @@ infisical: # -- Sets the name of the deployment within this chart name: infisical - # -- Automatically migrates new database schema when deploying - autoDatabaseSchemaMigration: true - - # -- redeployOnSecretChange is used to reload the Infisical instance when the Kubernetes secret referenced by `infisical.kubeSecretRef` is updated - redeployOnSecretChange: true - autoBootstrap: # -- Enable auto-bootstrap of the Infisical instance enabled: false @@ -71,7 +65,7 @@ infisical: # -- Image repository for the Infisical service repository: infisical/infisical # -- Specific version tag of the Infisical image. View the latest version here https://hub.docker.com/r/infisical/infisical - tag: "v0.93.1-postgres" + tag: "v0.151.0" # -- Pulls image only if not already present on the node pullPolicy: IfNotPresent # -- Secret references for pulling the image, if needed From 407a7e60758c6e1ac5f503e087e4a75264dfc917 Mon Sep 17 00:00:00 2001 From: x032205 Date: Tue, 21 Oct 2025 14:54:05 -0400 Subject: [PATCH 038/146] remove default from rotationIntervalSeconds --- .../src/db/migrations/20251015042917_pam-account-rotation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/db/migrations/20251015042917_pam-account-rotation.ts b/backend/src/db/migrations/20251015042917_pam-account-rotation.ts index cd9a7d19a..eee9fd1fd 100644 --- a/backend/src/db/migrations/20251015042917_pam-account-rotation.ts +++ b/backend/src/db/migrations/20251015042917_pam-account-rotation.ts @@ -10,7 +10,7 @@ export async function up(knex: Knex): Promise { ) { await knex.schema.alterTable(TableName.PamAccount, (t) => { t.boolean("rotationEnabled").notNullable().defaultTo(false); - t.integer("rotationIntervalSeconds").notNullable().defaultTo(2592000); + t.integer("rotationIntervalSeconds").notNullable(); t.timestamp("lastRotatedAt").nullable(); }); } From c68da1201886a6936705c1942597d01e08577d54 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 21 Oct 2025 15:54:46 -0300 Subject: [PATCH 039/146] docs: enhance login documentation with detailed authentication methods and examples --- docs/cli/commands/login.mdx | 203 ++++++++++++++++++++++++++++++++++-- 1 file changed, 196 insertions(+), 7 deletions(-) diff --git a/docs/cli/commands/login.mdx b/docs/cli/commands/login.mdx index f93e3b4b2..50b96baa1 100644 --- a/docs/cli/commands/login.mdx +++ b/docs/cli/commands/login.mdx @@ -9,22 +9,92 @@ infisical login ### Description -The CLI uses authentication to verify your identity. When you enter the correct email and password for your account, a token is generated and saved in your system Keyring to allow you to make future interactions with the CLI. +The CLI uses authentication to verify your identity. You can authenticate using: +- **Browser Login** (default): Opens a browser for authentication +- **Direct Login**: Provide email and password via flags or environment variables for non-interactive workflows +- **Interactive CLI Login**: Use the `--interactive` flag to enter credentials via CLI prompts + +When authenticated, a token is generated and saved in your system Keyring to allow you to make future interactions with the CLI. To change where the login credentials are stored, visit the [vaults command](./vault). If you have added multiple users, you can switch between the users by using the [user command](./user). - When you authenticate with **any other method than `user`**, an access token will be printed to the console upon successful login. This token can be used to authenticate with the Infisical API and the CLI by passing it in the `--token` flag when applicable. - - Use flag `--plain` along with `--silent` to print only the token in plain text when using a machine identity auth method. - + **JWT Token Output:** + - For **user authentication** with the `--plain` flag: outputs only the JWT access token (useful for scripting) + - For **machine identity authentication**: an access token is always printed to the console + + Use the `--plain` flag to print only the token in plain text, which is ideal for capturing in environment variables or CI/CD pipelines. ### Authentication Methods -The Infisical CLI supports multiple authentication methods. Below are the available authentication methods, with their respective flags. +The Infisical CLI supports two main categories of authentication: User Authentication and Machine Identity Authentication. + +#### User Authentication + +User authentication is designed for individual developers and supports multiple login flows. + + + + The User authentication method allows you to log in with your email and password. This method supports three different login flows: + + - **Browser Login** (default): Opens a browser for authentication + - **Direct Login**: Provide credentials via flags or environment variables for CI/CD + - **Interactive CLI Login**: Enter credentials via CLI prompts using `--interactive` + + + + + Your email address. Required for direct login along with `--password`. + + + Your password. Required for direct login along with `--email`. + + + Force interactive CLI login instead of browser-based authentication. + + + Output only the JWT token (useful for scripting and CI/CD). + + + + + + + **Browser Login (Default)** + ```bash + infisical login + ``` + + **Direct Login (CI/CD)** + ```bash + infisical login --email=user@example.com --password=your-password + + # Or using environment variables + export INFISICAL_EMAIL="user@example.com" + export INFISICAL_PASSWORD="your-password" + infisical login + ``` + + **Interactive CLI Login** + ```bash + infisical login --interactive + ``` + + **Plain Token Output (for scripting)** + ```bash + export INFISICAL_TOKEN=$(infisical login --email=user@example.com --password=your-password --plain) + ``` + + + + + +#### Machine Identity Authentication + +Machine identity authentication methods are designed for automated systems, services, and CI/CD pipelines. @@ -330,6 +400,59 @@ The login command supports a number of flags that you can use for different auth + + ```bash + infisical login --email= --password= + ``` + + #### Description + Email address for direct user login. Must be used together with `--password` for non-interactive authentication. + + + The `email` flag can be substituted with the `INFISICAL_EMAIL` environment variable. + + + + + ```bash + infisical login --email= --password= + ``` + + #### Description + Password for direct user login. Must be used together with `--email` for non-interactive authentication. + + + For security in CI/CD environments, prefer using the `INFISICAL_PASSWORD` environment variable instead of passing the password as a command-line flag. + + + + The `password` flag can be substituted with the `INFISICAL_PASSWORD` environment variable. + + + + + ```bash + infisical login --interactive + ``` + + #### Description + Forces interactive CLI login where you'll be prompted to enter your email and password in the terminal, instead of opening a browser. + + + + ```bash + infisical login --email= --password= --plain + ``` + + #### Description + When used with direct user login or machine identity authentication, outputs only the JWT access token without any additional formatting. This is useful for scripting and CI/CD pipelines where you need to capture the token. + + ```bash + # Example: Capture token in a variable + export INFISICAL_TOKEN=$(infisical login --email= --password= --plain) + ``` + + @@ -346,6 +469,72 @@ The login command supports a number of flags that you can use for different auth +### User Authentication Examples + +The following examples demonstrate different ways to authenticate as a user with the Infisical CLI. + + + + Direct login is ideal for CI/CD pipelines and automation scripts where browser-based authentication is not possible. + + #### Using Command-Line Flags + + ```bash + # Basic direct login + infisical login --email user@example.com --password "your-password" + + # With custom domain (US Cloud) + infisical login --email user@example.com --password "your-password" --domain https://app.infisical.com + + # With custom domain (EU Cloud) + infisical login --email user@example.com --password "your-password" --domain https://eu.infisical.com + + # Output only JWT token for scripting + export INFISICAL_TOKEN=$(infisical login --email user@example.com --password "your-password" --plain) + ``` + + #### Using Environment Variables (Recommended for CI/CD) + + ```bash + # Set credentials as environment variables + export INFISICAL_EMAIL="user@example.com" + export INFISICAL_PASSWORD="your-password" + export INFISICAL_API_URL="https://app.infisical.com/api" + + # Login without additional flags + infisical login + + # Or with plain output for token capture + export INFISICAL_TOKEN=$(infisical login --plain) + ``` + + + + Interactive login prompts you to enter credentials in the terminal instead of opening a browser. + + ```bash + # Force interactive CLI login + infisical login --interactive + ``` + + You'll be prompted to enter: + - Email address + - Password + + + + + By default, running `infisical login` without any flags opens your browser for authentication. + + ```bash + # Opens browser for authentication + infisical login + ``` + + The browser will open to the Infisical login page, and upon successful authentication, the CLI will be automatically authenticated. + + + ### Machine Identity Authentication Quick Start @@ -367,7 +556,7 @@ In this example we'll be using the `universal-auth` method to login to obtain an ``` - + ```bash infisical secrets --projectId= Date: Tue, 21 Oct 2025 23:20:22 +0400 Subject: [PATCH 040/146] Update hsm-fns.ts --- backend/src/ee/services/hsm/hsm-fns.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/ee/services/hsm/hsm-fns.ts b/backend/src/ee/services/hsm/hsm-fns.ts index 2603f80bd..f4d0b8801 100644 --- a/backend/src/ee/services/hsm/hsm-fns.ts +++ b/backend/src/ee/services/hsm/hsm-fns.ts @@ -31,8 +31,6 @@ export const initializeHsmModule = (envConfig: Pick Date: Wed, 22 Oct 2025 03:28:54 +0800 Subject: [PATCH 041/146] misc: added handling for non-string vault values for migration --- .../hc-vault/hc-vault-connection-fns.ts | 21 +++++++++++++++++-- .../external-migration-service.ts | 3 ++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/backend/src/services/app-connection/hc-vault/hc-vault-connection-fns.ts b/backend/src/services/app-connection/hc-vault/hc-vault-connection-fns.ts index 38f97700c..425c9c4d2 100644 --- a/backend/src/services/app-connection/hc-vault/hc-vault-connection-fns.ts +++ b/backend/src/services/app-connection/hc-vault/hc-vault-connection-fns.ts @@ -25,6 +25,23 @@ import { THCVaultMountResponse } from "./hc-vault-connection-types"; +// HashiCorp Vault stores JSON data, so values can be any valid JSON type +type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue }; + +export const convertVaultValueToString = (value: JsonValue): string => { + if (value === null) { + return ""; + } + if (typeof value === "string") { + return value; + } + if (typeof value === "number" || typeof value === "boolean") { + return String(value); + } + // For objects and arrays, serialize as JSON + return JSON.stringify(value); +}; + // Concurrency limit for HC Vault API requests to avoid rate limiting const HC_VAULT_CONCURRENCY_LIMIT = 20; @@ -598,7 +615,7 @@ export const getHCVaultSecretsForPath = async ( // For KV v2: /v1/{mount}/data/{path} const { data } = await requestWithHCVaultGateway<{ data: { - data: Record; // KV v2 has nested data structure + data: Record; // KV v2 has nested data structure, supports all JSON types metadata: { created_time: string; deletion_time: string; @@ -620,7 +637,7 @@ export const getHCVaultSecretsForPath = async ( // For KV v1: /v1/{mount}/{path} const { data } = await requestWithHCVaultGateway<{ - data: Record; // KV v1 has flat data structure + data: Record; // KV v1 has flat data structure, supports all JSON types lease_duration: number; lease_id: string; renewable: boolean; diff --git a/backend/src/services/external-migration/external-migration-service.ts b/backend/src/services/external-migration/external-migration-service.ts index 4192ffcd5..469b27bb3 100644 --- a/backend/src/services/external-migration/external-migration-service.ts +++ b/backend/src/services/external-migration/external-migration-service.ts @@ -16,6 +16,7 @@ import { AppConnection } from "../app-connection/app-connection-enums"; import { decryptAppConnectionCredentials } from "../app-connection/app-connection-fns"; import { TAppConnectionServiceFactory } from "../app-connection/app-connection-service"; import { + convertVaultValueToString, getHCVaultAuthMounts, getHCVaultKubernetesAuthRoles, getHCVaultSecretsForPath, @@ -581,7 +582,7 @@ export const externalMigrationServiceFactory = ({ projectId, secrets: Object.entries(vaultSecrets).map(([secretKey, secretValue]) => ({ secretKey, - secretValue + secretValue: convertVaultValueToString(secretValue) })) }); From 10cebfbbe29b824a6ef5b7def3e475e91195e19e Mon Sep 17 00:00:00 2001 From: Carlos Monastyrski Date: Tue, 21 Oct 2025 16:37:08 -0300 Subject: [PATCH 042/146] Check identitiesUsed instead of identityLimit on getPlan --- backend/src/ee/services/license/license-service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/ee/services/license/license-service.ts b/backend/src/ee/services/license/license-service.ts index fba9d0cca..817f4609c 100644 --- a/backend/src/ee/services/license/license-service.ts +++ b/backend/src/ee/services/license/license-service.ts @@ -212,9 +212,8 @@ export const licenseServiceFactory = ({ const membersUsed = await licenseDAL.countOfOrgMembers(orgId); currentPlan.membersUsed = membersUsed; const identityUsed = await licenseDAL.countOrgUsersAndIdentities(orgId); - currentPlan.identitiesUsed = identityUsed; - if (currentPlan.identityLimit && currentPlan.identityLimit !== identityUsed) { + if (currentPlan?.identitiesUsed && currentPlan.identitiesUsed !== identityUsed) { try { await licenseServerCloudApi.request.patch(`/api/license-server/v1/customers/${org.customerId}/cloud-plan`, { quantity: membersUsed, @@ -227,6 +226,7 @@ export const licenseServiceFactory = ({ ); } } + currentPlan.identitiesUsed = identityUsed; await keyStore.setItemWithExpiry( FEATURE_CACHE_KEY(org.id), From 98b2c556b8dc66b786997ebc61c98214284490a8 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 21 Oct 2025 16:45:57 -0300 Subject: [PATCH 043/146] docs: fix syntax error in login command example for fetching secrets --- docs/cli/commands/login.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cli/commands/login.mdx b/docs/cli/commands/login.mdx index 50b96baa1..16fef7985 100644 --- a/docs/cli/commands/login.mdx +++ b/docs/cli/commands/login.mdx @@ -558,7 +558,7 @@ In this example we'll be using the `universal-auth` method to login to obtain an ```bash - infisical secrets --projectId= --env=dev --recursive ``` This command will fetch all secrets from the `dev` environment in your project, including all secrets in subfolders. From 65b36e6232cfbfb4e4a3c88752a317c000babba6 Mon Sep 17 00:00:00 2001 From: x032205 Date: Tue, 21 Oct 2025 15:57:44 -0400 Subject: [PATCH 044/146] use __INFISICAL_UNCHANGED__ instead of empty string for unchanged placeholder --- .../pam-account/pam-account-service.ts | 23 +++++++++++++++---- .../pam-resource/pam-resource-service.ts | 5 +++- .../PamAccountForm/PostgresAccountForm.tsx | 2 +- .../shared/SqlAccountFields.tsx | 4 ++-- .../PamResourceForm/PostgresResourceForm.tsx | 2 +- .../shared/SqlRotateAccountFields.tsx | 4 ++-- 6 files changed, 29 insertions(+), 11 deletions(-) diff --git a/backend/src/ee/services/pam-account/pam-account-service.ts b/backend/src/ee/services/pam-account/pam-account-service.ts index 83e488231..2dfdec196 100644 --- a/backend/src/ee/services/pam-account/pam-account-service.ts +++ b/backend/src/ee/services/pam-account/pam-account-service.ts @@ -150,7 +150,12 @@ export const pamAccountServiceFactory = ({ return { ...(await decryptAccount(account, resource.projectId, kmsService)), - resource: { id: resource.id, name: resource.name, resourceType: resource.resourceType } + resource: { + id: resource.id, + name: resource.name, + resourceType: resource.resourceType, + rotationCredentialsConfigured: !!resource.encryptedRotationAccountCredentials + } }; } catch (err) { if (err instanceof DatabaseError && (err.error as { code: string })?.code === DatabaseErrorCode.UniqueViolation) { @@ -241,7 +246,7 @@ export const pamAccountServiceFactory = ({ // Logic to prevent overwriting unedited censored values const finalCredentials = { ...credentials }; - if (credentials.password === "******") { + if (credentials.password === "__INFISICAL_UNCHANGED__") { const decryptedCredentials = await decryptAccountCredentials({ encryptedCredentials: account.encryptedCredentials, projectId: account.projectId, @@ -269,7 +274,12 @@ export const pamAccountServiceFactory = ({ return { ...(await decryptAccount(updatedAccount, account.projectId, kmsService)), - resource: { id: resource.id, name: resource.name, resourceType: resource.resourceType } + resource: { + id: resource.id, + name: resource.name, + resourceType: resource.resourceType, + rotationCredentialsConfigured: !!resource.encryptedRotationAccountCredentials + } }; }; @@ -308,7 +318,12 @@ export const pamAccountServiceFactory = ({ return { ...(await decryptAccount(deletedAccount, account.projectId, kmsService)), - resource: { id: resource.id, name: resource.name, resourceType: resource.resourceType } + resource: { + id: resource.id, + name: resource.name, + resourceType: resource.resourceType, + rotationCredentialsConfigured: !!resource.encryptedRotationAccountCredentials + } }; }; diff --git a/backend/src/ee/services/pam-resource/pam-resource-service.ts b/backend/src/ee/services/pam-resource/pam-resource-service.ts index 9ec702b24..d97905dbe 100644 --- a/backend/src/ee/services/pam-resource/pam-resource-service.ts +++ b/backend/src/ee/services/pam-resource/pam-resource-service.ts @@ -194,7 +194,10 @@ export const pamResourceServiceFactory = ({ // Logic to prevent overwriting unedited censored values const finalCredentials = { ...rotationAccountCredentials }; - if (resource.encryptedRotationAccountCredentials && rotationAccountCredentials.password === "******") { + if ( + resource.encryptedRotationAccountCredentials && + rotationAccountCredentials.password === "__INFISICAL_UNCHANGED__" + ) { const decryptedCredentials = await decryptAccountCredentials({ encryptedCredentials: resource.encryptedRotationAccountCredentials, projectId: resource.projectId, diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx index c353a278b..17d68bdf0 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PostgresAccountForm.tsx @@ -34,7 +34,7 @@ export const PostgresAccountForm = ({ account, resourceId, resourceType, onSubmi ...account, credentials: { ...account.credentials, - password: "******" + password: "__INFISICAL_UNCHANGED__" } } : undefined diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/SqlAccountFields.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/SqlAccountFields.tsx index 7d9e85c44..0fd5760f3 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/SqlAccountFields.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/SqlAccountFields.tsx @@ -38,14 +38,14 @@ export const SqlAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { type={showPassword ? "text" : "password"} autoComplete="new-password" onFocus={() => { - if (isUpdate && field.value === "******") { + if (isUpdate && field.value === "__INFISICAL_UNCHANGED__") { field.onChange(""); } setShowPassword(true); }} onBlur={() => { if (isUpdate && field.value === "") { - field.onChange("******"); + field.onChange("__INFISICAL_UNCHANGED__"); } setShowPassword(false); }} diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx index 20ac710c3..2c53c89df 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx @@ -37,7 +37,7 @@ export const PostgresResourceForm = ({ resource, onSubmit }: Props) => { rotationAccountCredentials: resource.rotationAccountCredentials ? { ...resource.rotationAccountCredentials, - password: "******" + password: "__INFISICAL_UNCHANGED__" } : resource.rotationAccountCredentials } diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx index 869594140..6ce92b8e6 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx @@ -55,14 +55,14 @@ export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { type={showPassword ? "text" : "password"} autoComplete="new-password" onFocus={() => { - if (isUpdate && field.value === "******") { + if (isUpdate && field.value === "__INFISICAL_UNCHANGED__") { field.onChange(""); } setShowPassword(true); }} onBlur={() => { if (isUpdate && field.value === "") { - field.onChange("******"); + field.onChange("__INFISICAL_UNCHANGED__"); } setShowPassword(false); }} From 85daaf806e536f749140a94ffc7bdc0c4085f41f Mon Sep 17 00:00:00 2001 From: x032205 Date: Tue, 21 Oct 2025 16:21:52 -0400 Subject: [PATCH 045/146] Make rotationIntervalSeconds nullable --- .../db/migrations/20251015042917_pam-account-rotation.ts | 2 +- backend/src/db/schemas/pam-accounts.ts | 2 +- .../routes/v1/pam-account-routers/pam-account-endpoints.ts | 2 +- backend/src/ee/services/audit-log/audit-log-types.ts | 4 ++-- backend/src/ee/services/pam-account/pam-account-dal.ts | 1 + .../src/ee/services/pam-resource/pam-resource-schemas.ts | 4 ++-- frontend/src/hooks/api/pam/types/base-account.ts | 2 +- .../components/PamAccountForm/RotateAccountFields.tsx | 6 +++--- 8 files changed, 12 insertions(+), 11 deletions(-) diff --git a/backend/src/db/migrations/20251015042917_pam-account-rotation.ts b/backend/src/db/migrations/20251015042917_pam-account-rotation.ts index eee9fd1fd..4e9fc90d4 100644 --- a/backend/src/db/migrations/20251015042917_pam-account-rotation.ts +++ b/backend/src/db/migrations/20251015042917_pam-account-rotation.ts @@ -10,7 +10,7 @@ export async function up(knex: Knex): Promise { ) { await knex.schema.alterTable(TableName.PamAccount, (t) => { t.boolean("rotationEnabled").notNullable().defaultTo(false); - t.integer("rotationIntervalSeconds").notNullable(); + t.integer("rotationIntervalSeconds").nullable(); t.timestamp("lastRotatedAt").nullable(); }); } diff --git a/backend/src/db/schemas/pam-accounts.ts b/backend/src/db/schemas/pam-accounts.ts index 9bcfa5cec..7e78e0874 100644 --- a/backend/src/db/schemas/pam-accounts.ts +++ b/backend/src/db/schemas/pam-accounts.ts @@ -20,7 +20,7 @@ export const PamAccountsSchema = z.object({ createdAt: z.date(), updatedAt: z.date(), rotationEnabled: z.boolean().default(false), - rotationIntervalSeconds: z.number().default(2592000), + rotationIntervalSeconds: z.number().nullable().optional(), lastRotatedAt: z.date().nullable().optional() }); diff --git a/backend/src/ee/routes/v1/pam-account-routers/pam-account-endpoints.ts b/backend/src/ee/routes/v1/pam-account-routers/pam-account-endpoints.ts index dccaaa8ca..44e2a5ea1 100644 --- a/backend/src/ee/routes/v1/pam-account-routers/pam-account-endpoints.ts +++ b/backend/src/ee/routes/v1/pam-account-routers/pam-account-endpoints.ts @@ -23,7 +23,7 @@ export const registerPamResourceEndpoints = ({ name: C["name"]; description?: C["description"]; rotationEnabled: C["rotationEnabled"]; - rotationIntervalSeconds: C["rotationIntervalSeconds"]; + rotationIntervalSeconds?: C["rotationIntervalSeconds"]; }>; updateAccountSchema: z.ZodType<{ credentials?: C["credentials"]; diff --git a/backend/src/ee/services/audit-log/audit-log-types.ts b/backend/src/ee/services/audit-log/audit-log-types.ts index 94561e6d8..8569d764b 100644 --- a/backend/src/ee/services/audit-log/audit-log-types.ts +++ b/backend/src/ee/services/audit-log/audit-log-types.ts @@ -3798,7 +3798,7 @@ interface PamAccountCreateEvent { name: string; description?: string | null; rotationEnabled: boolean; - rotationIntervalSeconds: number; + rotationIntervalSeconds?: number | null; }; } @@ -3811,7 +3811,7 @@ interface PamAccountUpdateEvent { name?: string; description?: string | null; rotationEnabled?: boolean; - rotationIntervalSeconds?: number; + rotationIntervalSeconds?: number | null; }; } diff --git a/backend/src/ee/services/pam-account/pam-account-dal.ts b/backend/src/ee/services/pam-account/pam-account-dal.ts index e0377871c..4c8f5136a 100644 --- a/backend/src/ee/services/pam-account/pam-account-dal.ts +++ b/backend/src/ee/services/pam-account/pam-account-dal.ts @@ -49,6 +49,7 @@ export const pamAccountDALFactory = (db: TDbClient) => { const accounts = await dbClient(TableName.PamAccount) .innerJoin(TableName.PamResource, `${TableName.PamAccount}.resourceId`, `${TableName.PamResource}.id`) .whereNotNull(`${TableName.PamResource}.encryptedRotationAccountCredentials`) + .whereNotNull(`${TableName.PamAccount}.rotationIntervalSeconds`) .whereRaw( `COALESCE("${TableName.PamAccount}"."lastRotatedAt", "${TableName.PamAccount}"."createdAt") + "${TableName.PamAccount}"."rotationIntervalSeconds" * interval '1 second' < NOW()` ) diff --git a/backend/src/ee/services/pam-resource/pam-resource-schemas.ts b/backend/src/ee/services/pam-resource/pam-resource-schemas.ts index 8f4752f4e..7f6165d88 100644 --- a/backend/src/ee/services/pam-resource/pam-resource-schemas.ts +++ b/backend/src/ee/services/pam-resource/pam-resource-schemas.ts @@ -42,12 +42,12 @@ export const BaseCreatePamAccountSchema = z.object({ name: slugSchema({ field: "name" }), description: z.string().max(512).nullable().optional(), rotationEnabled: z.boolean(), - rotationIntervalSeconds: z.number().min(3600) + rotationIntervalSeconds: z.number().min(3600).nullable().optional() }); export const BaseUpdatePamAccountSchema = z.object({ name: slugSchema({ field: "name" }).optional(), description: z.string().max(512).nullable().optional(), rotationEnabled: z.boolean().optional(), - rotationIntervalSeconds: z.number().min(3600).optional() + rotationIntervalSeconds: z.number().min(3600).nullable().optional() }); diff --git a/frontend/src/hooks/api/pam/types/base-account.ts b/frontend/src/hooks/api/pam/types/base-account.ts index 09ad6550d..20cb7aa60 100644 --- a/frontend/src/hooks/api/pam/types/base-account.ts +++ b/frontend/src/hooks/api/pam/types/base-account.ts @@ -14,7 +14,7 @@ export interface TBasePamAccount { name: string; description?: string | null; rotationEnabled: boolean; - rotationIntervalSeconds: number; + rotationIntervalSeconds?: number | null; lastRotatedAt?: string | null; createdAt: string; updatedAt: string; diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/RotateAccountFields.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/RotateAccountFields.tsx index 2739e1cd5..a73fad58b 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/RotateAccountFields.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/RotateAccountFields.tsx @@ -6,7 +6,7 @@ import { FormControl, Select, SelectItem, Switch, Tooltip } from "@app/component export const rotateAccountFieldsSchema = z.object({ rotationEnabled: z.boolean(), - rotationIntervalSeconds: z.number() + rotationIntervalSeconds: z.number().nullable().optional() }); export const RotateAccountFields = ({ @@ -16,7 +16,7 @@ export const RotateAccountFields = ({ }) => { const { control, watch } = useFormContext<{ rotationEnabled: boolean; - rotationIntervalSeconds: number; + rotationIntervalSeconds?: number | null; }>(); const rotationEnabled = watch("rotationEnabled"); @@ -62,7 +62,7 @@ export const RotateAccountFields = ({ className="mb-0" > setName(e.target.value)} - placeholder="Enter gateway name..." - isError={!isNameValid} - /> - - - { - if ((newValue as SingleValue<{ id: string }>)?.id === "_create") { - navigate({ - search: (prev) => ({ ...prev, selectedTab: "relays", action: "deploy-relay" }) - }); - return; - } - - setRelay(newValue as SingleValue<{ id: string; name: string }>); - }} - isLoading={isRelaysLoading} - options={[ - { - id: "_create", - name: "Deploy New Relay" - }, - ...(relays || []) - ]} - placeholder="Select relay..." - getOptionLabel={(option) => option.name} - getOptionValue={(option) => option.id} - components={{ Option: RelayOption }} - /> - - - - handleIdentityChange( - e as SingleValue<{ - id: string; - name: string; - }> - ) - } - isLoading={isIdentitiesLoading} - placeholder="Select identity..." - options={identityMembershipOrgs.map((membership) => membership.identity)} - getOptionValue={(option) => option.id} - getOptionLabel={(option) => option.name} - /> - - -
- - { - navigator.clipboard.writeText(command); - - createNotification({ - text: "Command copied to clipboard", - type: "info" - }); - }} - className={twMerge("w-10", !isCommandReady && "pointer-events-none opacity-50")} - isDisabled={!isCommandReady} - > - - -
- - Install the Infisical CLI - - - - - ); -}; diff --git a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployRelayModal.tsx b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployRelayModal.tsx deleted file mode 100644 index 61501c40f..000000000 --- a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/DeployRelayModal.tsx +++ /dev/null @@ -1,205 +0,0 @@ -import { useEffect, useMemo, useState } from "react"; -import { SingleValue } from "react-select"; -import { faCopy, faUpRightFromSquare } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { twMerge } from "tailwind-merge"; - -import { createNotification } from "@app/components/notifications"; -import { - FilterableSelect, - FormLabel, - IconButton, - Input, - Modal, - ModalContent -} from "@app/components/v2"; -import { useOrganization } from "@app/context"; -import { - useAddIdentityTokenAuth, - useCreateTokenIdentityTokenAuth, - useGetIdentityMembershipOrgs, - useGetIdentityTokenAuth -} from "@app/hooks/api"; -import { slugSchema } from "@app/lib/schemas"; - -type Props = { - isOpen: boolean; - onOpenChange: (isOpen: boolean) => void; -}; - -export const DeployRelayModal = ({ isOpen, onOpenChange }: Props) => { - const { protocol, hostname, port } = window.location; - const portSuffix = port && port !== "80" ? `:${port}` : ""; - const siteURL = `${protocol}//${hostname}${portSuffix}`; - - const [name, setName] = useState(""); - const [host, setHost] = useState(""); - const [identity, setIdentity] = useState(null); - const [identityToken, setIdentityToken] = useState(""); - - useEffect(() => { - if (!isOpen) { - setName(""); - setHost(""); - setIdentity(null); - setIdentityToken(""); - } - }, [isOpen]); - - const { currentOrg } = useOrganization(); - const organizationId = currentOrg?.id || ""; - - const { data: identityMembershipOrgsData, isPending: isIdentitiesLoading } = - useGetIdentityMembershipOrgs({ - organizationId, - limit: 20000 - }); - const identityMembershipOrgs = identityMembershipOrgsData?.identityMemberships || []; - - const { mutateAsync: createToken } = useCreateTokenIdentityTokenAuth(); - const { mutateAsync: addIdentityTokenAuth } = useAddIdentityTokenAuth(); - const { refetch } = useGetIdentityTokenAuth(identity?.id ?? ""); - - useEffect(() => { - const generateToken = async () => { - if (!identity) return; - - try { - const { data: identityTokenAuth } = await refetch(); - if (!identityTokenAuth) { - await addIdentityTokenAuth({ - identityId: identity.id, - organizationId, - accessTokenTTL: 2592000, - accessTokenMaxTTL: 2592000, - accessTokenNumUsesLimit: 0, - accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }] - }); - createNotification({ - text: "Automatically enabled token authentication for this identity.", - type: "info" - }); - } - - const token = await createToken({ - identityId: identity.id, - name: "relay token (autogenerated)" - }); - setIdentityToken(token.accessToken); - createNotification({ - text: "Automatically generated a token for this identity.", - type: "info" - }); - } catch (err) { - console.error(err); - createNotification({ - text: "Failed to generate token for identity", - type: "error" - }); - setIdentityToken(""); - } - }; - - generateToken(); - }, [identity, organizationId, refetch, addIdentityTokenAuth, createToken]); - - const handleIdentityChange = (selectedIdentity: SingleValue<{ id: string; name: string }>) => { - setIdentity(selectedIdentity); - setIdentityToken(""); - }; - - const isNameValid = useMemo(() => !name || slugSchema().safeParse(name).success, [name]); - - const isCommandReady = useMemo( - () => !!name && !!host && isNameValid && !!identityToken, - [name, isNameValid, host, identityToken] - ); - - const command = useMemo( - () => - `infisical relay start --name=${name} --domain=${siteURL} --host=${host} --token=${identityToken}`, - [name, siteURL, host, identityToken] - ); - - return ( - - - - setName(e.target.value)} - placeholder="Enter relay name..." - isError={!isNameValid} - /> - - - setHost(e.target.value)} placeholder="0.0.0.0" /> - - - - handleIdentityChange( - e as SingleValue<{ - id: string; - name: string; - }> - ) - } - isLoading={isIdentitiesLoading} - placeholder="Select identity..." - options={identityMembershipOrgs.map((membership) => membership.identity)} - getOptionValue={(option) => option.id} - getOptionLabel={(option) => option.name} - /> - - -
- - { - navigator.clipboard.writeText(command); - - createNotification({ - text: "Command copied to clipboard", - type: "info" - }); - }} - className={twMerge("w-10", !isCommandReady && "pointer-events-none opacity-50")} - isDisabled={!isCommandReady} - > - - -
- - Install the Infisical CLI - - -
-
- ); -}; diff --git a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayCliDeploymentMethod.tsx b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayCliDeploymentMethod.tsx new file mode 100644 index 000000000..279dc61c9 --- /dev/null +++ b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayCliDeploymentMethod.tsx @@ -0,0 +1,297 @@ +import { useMemo, useState } from "react"; +import { SingleValue } from "react-select"; +import { faCopy, faUpRightFromSquare } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useNavigate } from "@tanstack/react-router"; +import { z } from "zod"; + +import { createNotification } from "@app/components/notifications"; +import { + Button, + FilterableSelect, + FormLabel, + IconButton, + Input, + ModalClose +} from "@app/components/v2"; +import { ROUTE_PATHS } from "@app/const/routes"; +import { useOrganization } from "@app/context"; +import { + useAddIdentityTokenAuth, + useCreateTokenIdentityTokenAuth, + useGetIdentityMembershipOrgs, + useGetIdentityTokenAuth, + useGetRelays +} from "@app/hooks/api"; +import { slugSchema } from "@app/lib/schemas"; + +import { RelayOption } from "./RelayOption"; + +const formSchema = z.object({ + name: slugSchema({ field: "name" }), + instanceDomain: z.string().url("Must be a valid URL").or(z.literal("")), + relay: z + .object( + { + id: z.string(), + name: z.string() + }, + { required_error: "Relay is required" } + ) + .nullable() + .refine((val) => val !== null, { message: "Relay is required" }), + identity: z + .object( + { + id: z.string(), + name: z.string() + }, + { required_error: "Identity is required" } + ) + .nullable() + .refine((val) => val !== null, { message: "Identity is required" }) +}); + +export const GatewayCliDeploymentMethod = () => { + const { protocol, hostname, port } = window.location; + const portSuffix = port && port !== "80" ? `:${port}` : ""; + const siteURL = `${protocol}//${hostname}${portSuffix}`; + + const navigate = useNavigate({ + from: ROUTE_PATHS.Organization.NetworkingPage.path + }); + + const [step, setStep] = useState<"form" | "command">("form"); + const [name, setName] = useState(""); + const [instanceDomain, setInstanceDomain] = useState(siteURL); + const [relay, setRelay] = useState(null); + const [identity, setIdentity] = useState(null); + const [identityToken, setIdentityToken] = useState(""); + const [formErrors, setFormErrors] = useState([]); + + const errors = useMemo(() => { + const errorMap: Record = {}; + formErrors.forEach((issue) => { + if (issue.path.length > 0) { + errorMap[String(issue.path[0])] = issue.message; + } + }); + return errorMap; + }, [formErrors]); + + const { data: relays, isPending: isRelaysLoading } = useGetRelays(); + + const { currentOrg } = useOrganization(); + const organizationId = currentOrg?.id || ""; + + const { data: identityMembershipOrgsData, isPending: isIdentitiesLoading } = + useGetIdentityMembershipOrgs({ + organizationId, + limit: 20000 + }); + const identityMembershipOrgs = identityMembershipOrgsData?.identityMemberships || []; + + const { mutateAsync: createToken, isPending: isCreatingToken } = + useCreateTokenIdentityTokenAuth(); + const { mutateAsync: addIdentityTokenAuth, isPending: isAddingTokenAuth } = + useAddIdentityTokenAuth(); + const { refetch } = useGetIdentityTokenAuth(identity?.id ?? ""); + + const handleGenerateCommand = async () => { + setFormErrors([]); + const validation = formSchema.safeParse({ name, relay, identity, instanceDomain }); + if (!validation.success) { + setFormErrors(validation.error.issues); + return; + } + + const validatedIdentity = validation.data.identity; + + try { + const { data: identityTokenAuth } = await refetch(); + if (!identityTokenAuth) { + await addIdentityTokenAuth({ + identityId: validatedIdentity.id, + organizationId, + accessTokenTTL: 2592000, + accessTokenMaxTTL: 2592000, + accessTokenNumUsesLimit: 0, + accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }] + }); + createNotification({ + text: "Automatically enabled token authentication for this identity.", + type: "info" + }); + } + + const token = await createToken({ + identityId: validatedIdentity.id, + name: "gateway token (autogenerated)" + }); + setIdentityToken(token.accessToken); + createNotification({ + text: "Automatically generated a token for this identity.", + type: "info" + }); + setStep("command"); + } catch (err) { + console.error(err); + createNotification({ + text: "Failed to generate token for identity", + type: "error" + }); + setIdentityToken(""); + } + }; + + const command = useMemo(() => { + const domainFlag = instanceDomain ? ` --domain=${instanceDomain}` : ""; + return `infisical gateway start --name=${name} --relay=${ + relay?.name || "" + }${domainFlag} --token=${identityToken}`; + }, [name, relay, identityToken, instanceDomain]); + + if (step === "command") { + return ( + <> + +
+ + { + navigator.clipboard.writeText(command); + createNotification({ + text: "Command copied to clipboard", + type: "info" + }); + }} + className="w-10" + > + + +
+ + Install the Infisical CLI + + +
+ + + +
+ + ); + } + + return ( + <> + + setName(e.target.value)} + placeholder="Enter gateway name..." + isError={Boolean(errors.name)} + /> + {errors.name &&

{errors.name}

} + + + { + if ((newValue as SingleValue<{ id: string }>)?.id === "_create") { + navigate({ + search: (prev) => ({ ...prev, selectedTab: "relays", action: "deploy-relay" }) + }); + return; + } + + setRelay(newValue as SingleValue<{ id: string; name: string }>); + }} + isLoading={isRelaysLoading} + options={[ + { + id: "_create", + name: "Deploy New Relay" + }, + ...(relays || []) + ]} + placeholder="Select relay..." + getOptionLabel={(option) => option.name} + getOptionValue={(option) => option.id} + components={{ Option: RelayOption }} + /> + {errors.relay &&

{errors.relay}

} + + + setInstanceDomain(e.target.value)} + placeholder="https://app.infisical.com" + isError={Boolean(errors.instanceDomain)} + /> + {errors.instanceDomain && ( +

{errors.instanceDomain}

+ )} + + + + setIdentity( + e as SingleValue<{ + id: string; + name: string; + }> + ) + } + isLoading={isIdentitiesLoading} + placeholder="Select identity..." + options={identityMembershipOrgs.map((membership) => membership.identity)} + getOptionValue={(option) => option.id} + getOptionLabel={(option) => option.name} + /> + {errors.identity &&

{errors.identity}

} + +
+ + + + +
+ + ); +}; diff --git a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayDeployModal.tsx b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayDeployModal.tsx new file mode 100644 index 000000000..170ea2eab --- /dev/null +++ b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayDeployModal.tsx @@ -0,0 +1,45 @@ +import { useState } from "react"; + +import { Modal, ModalContent } from "@app/components/v2"; +import { GatewayDeploymentMethodSelect } from "@app/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayDeploymentMethodSelect"; + +import { GatewayCliDeploymentMethod } from "./GatewayCliDeploymentMethod"; + +type Props = { + isOpen: boolean; + onOpenChange: (isOpen: boolean) => void; +}; + +export const GatewayDeploymentInfoMap = { + cli: { name: "CLI", image: "SSH.png", component: GatewayCliDeploymentMethod } +} as const; + +export type GatewayDeploymentMethod = keyof typeof GatewayDeploymentInfoMap; + +const Content = () => { + const [selectedMethod, setSelectedMethod] = useState(null); + + if (selectedMethod) { + const ComponentToRender = GatewayDeploymentInfoMap[selectedMethod]?.component; + if (ComponentToRender) { + return ; + } + } + + return ; +}; + +export const GatewayDeployModal = ({ isOpen, onOpenChange }: Props) => { + return ( + + + + + + ); +}; diff --git a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayDeploymentMethodSelect.tsx b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayDeploymentMethodSelect.tsx new file mode 100644 index 000000000..0a1fd5e12 --- /dev/null +++ b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayDeploymentMethodSelect.tsx @@ -0,0 +1,56 @@ +import { useMemo } from "react"; + +import { + GatewayDeploymentInfoMap, + GatewayDeploymentMethod +} from "@app/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayDeployModal"; + +type Props = { + onSelect: (method: GatewayDeploymentMethod) => void; +}; + +export const GatewayDeploymentMethodSelect = ({ onSelect }: Props) => { + const deploymentOptions = useMemo( + () => + (Object.keys(GatewayDeploymentInfoMap) as GatewayDeploymentMethod[]).map((method) => ({ + method, + name: GatewayDeploymentInfoMap[method].name, + image: GatewayDeploymentInfoMap[method].image + })), + [] + ); + + const handleResourceSelect = (method: GatewayDeploymentMethod) => { + onSelect(method); + }; + + return ( +
+ {deploymentOptions.map((option) => { + const { image, name } = option; + + return ( + + ); + })} +
+ ); +}; diff --git a/frontend/src/pages/organization/NetworkingPage/components/RelayTab/RelayTab.tsx b/frontend/src/pages/organization/NetworkingPage/components/RelayTab/RelayTab.tsx index 8c62bae1c..9ca3e1318 100644 --- a/frontend/src/pages/organization/NetworkingPage/components/RelayTab/RelayTab.tsx +++ b/frontend/src/pages/organization/NetworkingPage/components/RelayTab/RelayTab.tsx @@ -46,7 +46,7 @@ import { withPermission } from "@app/hoc"; import { usePopUp } from "@app/hooks"; import { useDeleteRelayById, useGetRelays } from "@app/hooks/api/relays"; -import { DeployRelayModal } from "../GatewayTab/components/DeployRelayModal"; +import { RelayDeployModal } from "./components/RelayDeployModal"; const RelayHealthStatus = ({ heartbeat }: { heartbeat?: string }) => { const heartbeatDate = heartbeat ? new Date(heartbeat) : null; @@ -258,7 +258,7 @@ export const RelayTab = withPermission( deleteKey="confirm" onDeleteApproved={() => handleDeleteRelay()} /> - handlePopUpToggle("deployRelay", isOpen)} /> diff --git a/frontend/src/pages/organization/NetworkingPage/components/RelayTab/components/RelayCliDeploymentMethod.tsx b/frontend/src/pages/organization/NetworkingPage/components/RelayTab/components/RelayCliDeploymentMethod.tsx new file mode 100644 index 000000000..543d31bae --- /dev/null +++ b/frontend/src/pages/organization/NetworkingPage/components/RelayTab/components/RelayCliDeploymentMethod.tsx @@ -0,0 +1,268 @@ +import { useMemo, useState } from "react"; +import { SingleValue } from "react-select"; +import { faCopy, faUpRightFromSquare } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { z } from "zod"; + +import { createNotification } from "@app/components/notifications"; +import { + Button, + FilterableSelect, + FormLabel, + IconButton, + Input, + ModalClose +} from "@app/components/v2"; +import { useOrganization } from "@app/context"; +import { + useAddIdentityTokenAuth, + useCreateTokenIdentityTokenAuth, + useGetIdentityMembershipOrgs, + useGetIdentityTokenAuth +} from "@app/hooks/api"; +import { slugSchema } from "@app/lib/schemas"; + +const formSchema = z.object({ + name: slugSchema({ field: "name" }), + host: z.string().min(1, "Host is required"), + + instanceDomain: z.string().url("Must be a valid URL").or(z.literal("")), + identity: z + .object( + { + id: z.string(), + name: z.string() + }, + { required_error: "Identity is required" } + ) + .nullable() + .refine((val) => val !== null, { message: "Identity is required" }) +}); + +export const RelayCliDeploymentMethod = () => { + const { protocol, hostname, port } = window.location; + const portSuffix = port && port !== "80" ? `:${port}` : ""; + const siteURL = `${protocol}//${hostname}${portSuffix}`; + + const [step, setStep] = useState<"form" | "command">("form"); + const [name, setName] = useState(""); + const [host, setHost] = useState(""); + + const [instanceDomain, setInstanceDomain] = useState(siteURL); + const [identity, setIdentity] = useState(null); + const [identityToken, setIdentityToken] = useState(""); + const [formErrors, setFormErrors] = useState([]); + + const errors = useMemo(() => { + const errorMap: Record = {}; + formErrors.forEach((issue) => { + if (issue.path.length > 0) { + errorMap[String(issue.path[0])] = issue.message; + } + }); + return errorMap; + }, [formErrors]); + + const { currentOrg } = useOrganization(); + const organizationId = currentOrg?.id || ""; + + const { data: identityMembershipOrgsData, isPending: isIdentitiesLoading } = + useGetIdentityMembershipOrgs({ + organizationId, + limit: 20000 + }); + const identityMembershipOrgs = identityMembershipOrgsData?.identityMemberships || []; + + const { mutateAsync: createToken, isPending: isCreatingToken } = + useCreateTokenIdentityTokenAuth(); + const { mutateAsync: addIdentityTokenAuth, isPending: isAddingTokenAuth } = + useAddIdentityTokenAuth(); + const { refetch } = useGetIdentityTokenAuth(identity?.id ?? ""); + + const handleGenerateCommand = async () => { + setFormErrors([]); + const validation = formSchema.safeParse({ name, host, instanceDomain, identity }); + if (!validation.success) { + setFormErrors(validation.error.issues); + return; + } + + const validatedIdentity = validation.data.identity; + + try { + const { data: identityTokenAuth } = await refetch(); + if (!identityTokenAuth) { + await addIdentityTokenAuth({ + identityId: validatedIdentity.id, + organizationId, + accessTokenTTL: 2592000, + accessTokenMaxTTL: 2592000, + accessTokenNumUsesLimit: 0, + accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }] + }); + createNotification({ + text: "Automatically enabled token authentication for this identity.", + type: "info" + }); + } + + const token = await createToken({ + identityId: validatedIdentity.id, + name: "relay token (autogenerated)" + }); + setIdentityToken(token.accessToken); + createNotification({ + text: "Automatically generated a token for this identity.", + type: "info" + }); + setStep("command"); + } catch (err) { + console.error(err); + createNotification({ + text: "Failed to generate token for identity", + type: "error" + }); + setIdentityToken(""); + } + }; + + const handleIdentityChange = ( + selectedIdentity: SingleValue<{ + id: string; + name: string; + }> + ) => { + setIdentity(selectedIdentity); + }; + + const command = useMemo(() => { + const domainFlag = instanceDomain ? ` --domain=${instanceDomain}` : ""; + return `infisical relay start --name=${name}${domainFlag} --host=${host} --token=${identityToken}`; + }, [name, instanceDomain, host, identityToken]); + + if (step === "command") { + return ( + <> + +
+ + { + navigator.clipboard.writeText(command); + createNotification({ + text: "Command copied to clipboard", + type: "info" + }); + }} + className="w-10" + > + + +
+ + Install the Infisical CLI + + +
+ + + +
+ + ); + } + + return ( + <> + + setName(e.target.value)} + placeholder="Enter relay name..." + isError={Boolean(errors.name)} + /> + {errors.name &&

{errors.name}

} + + + setHost(e.target.value)} + placeholder="0.0.0.0" + isError={Boolean(errors.host)} + /> + {errors.host &&

{errors.host}

} + + + setInstanceDomain(e.target.value)} + placeholder="https://app.infisical.com" + isError={Boolean(errors.instanceDomain)} + /> + {errors.instanceDomain && ( +

{errors.instanceDomain}

+ )} + + + + handleIdentityChange( + e as SingleValue<{ + id: string; + name: string; + }> + ) + } + isLoading={isIdentitiesLoading} + placeholder="Select identity..." + options={identityMembershipOrgs.map((membership) => membership.identity)} + getOptionValue={(option) => option.id} + getOptionLabel={(option) => option.name} + /> + {errors.identity &&

{errors.identity}

} + +
+ + + + +
+ + ); +}; diff --git a/frontend/src/pages/organization/NetworkingPage/components/RelayTab/components/RelayDeployModal.tsx b/frontend/src/pages/organization/NetworkingPage/components/RelayTab/components/RelayDeployModal.tsx new file mode 100644 index 000000000..496ecb762 --- /dev/null +++ b/frontend/src/pages/organization/NetworkingPage/components/RelayTab/components/RelayDeployModal.tsx @@ -0,0 +1,45 @@ +import { useState } from "react"; + +import { Modal, ModalContent } from "@app/components/v2"; +import { RelayDeploymentMethodSelect } from "@app/pages/organization/NetworkingPage/components/RelayTab/components/RelayDeploymentMethodSelect"; + +import { RelayCliDeploymentMethod } from "./RelayCliDeploymentMethod"; + +type Props = { + isOpen: boolean; + onOpenChange: (isOpen: boolean) => void; +}; + +export const RelayDeploymentInfoMap = { + cli: { name: "CLI", image: "SSH.png", component: RelayCliDeploymentMethod } +} as const; + +export type RelayDeploymentMethod = keyof typeof RelayDeploymentInfoMap; + +const Content = () => { + const [selectedMethod, setSelectedMethod] = useState(null); + + if (selectedMethod) { + const ComponentToRender = RelayDeploymentInfoMap[selectedMethod]?.component; + if (ComponentToRender) { + return ; + } + } + + return ; +}; + +export const RelayDeployModal = ({ isOpen, onOpenChange }: Props) => { + return ( + + + + + + ); +}; diff --git a/frontend/src/pages/organization/NetworkingPage/components/RelayTab/components/RelayDeploymentMethodSelect.tsx b/frontend/src/pages/organization/NetworkingPage/components/RelayTab/components/RelayDeploymentMethodSelect.tsx new file mode 100644 index 000000000..cb21499e4 --- /dev/null +++ b/frontend/src/pages/organization/NetworkingPage/components/RelayTab/components/RelayDeploymentMethodSelect.tsx @@ -0,0 +1,56 @@ +import { useMemo } from "react"; + +import { + RelayDeploymentInfoMap, + RelayDeploymentMethod +} from "@app/pages/organization/NetworkingPage/components/RelayTab/components/RelayDeployModal"; + +type Props = { + onSelect: (method: RelayDeploymentMethod) => void; +}; + +export const RelayDeploymentMethodSelect = ({ onSelect }: Props) => { + const deploymentOptions = useMemo( + () => + (Object.keys(RelayDeploymentInfoMap) as RelayDeploymentMethod[]).map((method) => ({ + method, + name: RelayDeploymentInfoMap[method].name, + image: RelayDeploymentInfoMap[method].image + })), + [] + ); + + const handleResourceSelect = (method: RelayDeploymentMethod) => { + onSelect(method); + }; + + return ( +
+ {deploymentOptions.map((option) => { + const { image, name } = option; + + return ( + + ); + })} +
+ ); +}; From e6a76187a28216825d535f6eaf74845c84e5fc80 Mon Sep 17 00:00:00 2001 From: x032205 Date: Wed, 22 Oct 2025 03:35:33 -0400 Subject: [PATCH 052/146] improve UI & greptile review fixes --- .../components/GatewayCliDeploymentMethod.tsx | 10 +++++----- .../components/GatewayDeploymentMethodSelect.tsx | 10 ++++------ .../NetworkingPage/components/RelayTab/RelayTab.tsx | 2 +- .../RelayTab/components/RelayCliDeploymentMethod.tsx | 10 +++++----- .../components/RelayDeploymentMethodSelect.tsx | 10 ++++------ 5 files changed, 19 insertions(+), 23 deletions(-) diff --git a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayCliDeploymentMethod.tsx b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayCliDeploymentMethod.tsx index 279dc61c9..a98853bbb 100644 --- a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayCliDeploymentMethod.tsx +++ b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayCliDeploymentMethod.tsx @@ -125,25 +125,25 @@ export const GatewayCliDeploymentMethod = () => { accessTokenTrustedIps: [{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }] }); createNotification({ - text: "Automatically enabled token authentication for this identity.", - type: "info" + text: "Token authentication has been automatically enabled for the selected identity. By default, it is configured to allow all IP addresses with a default token TTL of 30 days. You can manage these settings in Access Control.", + type: "warning" }); } const token = await createToken({ identityId: validatedIdentity.id, - name: "gateway token (autogenerated)" + name: `gateway token for ${name} (autogenerated)` }); setIdentityToken(token.accessToken); createNotification({ - text: "Automatically generated a token for this identity.", + text: "Automatically generated a token for the selected identity.", type: "info" }); setStep("command"); } catch (err) { console.error(err); createNotification({ - text: "Failed to generate token for identity", + text: "Failed to generate token for the selected identity", type: "error" }); setIdentityToken(""); diff --git a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayDeploymentMethodSelect.tsx b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayDeploymentMethodSelect.tsx index 0a1fd5e12..099c7d791 100644 --- a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayDeploymentMethodSelect.tsx +++ b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayDeploymentMethodSelect.tsx @@ -27,21 +27,19 @@ export const GatewayDeploymentMethodSelect = ({ onSelect }: Props) => { return (
{deploymentOptions.map((option) => { - const { image, name } = option; + const { image, name, method } = option; return (
-
-

Price

-

- {subscription.status === "trialing" - ? "$0.00 / month" - : `${formatAmount(data.amount)} / ${data.interval}`} -

-
+ {subscription.slug !== "enterprise" ? ( +
+

Price

+

+ {subscription.status === "trialing" ? ( + "$0.00 / month" + ) : ( + <> + {formatAmount(totalAmount)} / {data.interval} + {(subscription.slug === "pro" || subscription.slug === "pro-annual") && ( + 1 ? "users" : "user"} and ${data.identities} ${data.identities > 1 ? "machine identities" : "machine identity"}.`} + className="max-w-lg" + > + + + )} + + )} +

+
+ ) : null}

Subscription renews on

From f1e1e5b0c793126b4c1837623ab74d84c78ef29d Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Wed, 22 Oct 2025 22:18:45 +0530 Subject: [PATCH 060/146] fix: SDK contribution docs --- .../contributing/getting-started/overview.mdx | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/docs/contributing/getting-started/overview.mdx b/docs/contributing/getting-started/overview.mdx index 35912fc8c..1d79002a4 100644 --- a/docs/contributing/getting-started/overview.mdx +++ b/docs/contributing/getting-started/overview.mdx @@ -7,20 +7,20 @@ To set a strong foundation, this section outlines how we, the community and memb should approach the development and contribution process. ## Code-bases + Infisical has two major code-bases. One for the platform code, and one for SDKs. The contribution process has some key differences between the two, so we've split the documentation into two sections: - The [Infisical Platform](https://github.com/Infisical/infisical), the Infisical platform itself. -- The [Infisical SDK](https://infisical.com/docs/sdks/overview), the official Infisical client SDKs. - - - - - The Infisical platform is the core of the Infisical ecosystem. - - - The SDKs are the official Infisical client libraries, used by developers to easily interact with the Infisical platform. - - +- The Infisical SDKs, please refer to the each individual SDK documentation for more information. + - [Node.js SDK](https://github.com/Infisical/node-sdk-v2) + - [Python SDK](https://github.com/Infisical/python-sdk-official) + - [Java SDK](https://github.com/Infisical/java-sdk) + - [.NET SDK](https://github.com/Infisical/infisical-dotnet-sdk) + - [Go SDK](https://github.com/Infisical/go-sdk) + - [C++ SDK](https://github.com/Infisical/infisical-cpp-sdk) + - [PHP SDK](https://github.com/Infisical/php-sdk) + - [Rust SDK](https://github.com/Infisical/rust-sdk) + - [Ruby SDK](https://github.com/infisical/sdk) ## Community @@ -45,15 +45,12 @@ If you're ever in doubt about whether or not a proposed feature aligns with Infi ## Writing and submitting code -Anyone can contribute code to Infisical. To get started, check out the local development guides for each language. - -- Local development guide for Platform is [here](/contributing/platform/developing). -- Local development guide for SDK is [here](/contributing/sdk/developing). +Anyone can contribute code to Infisical. To get started, check out the local development guide for the platform: +- Local development guide for Platform is [here](/contributing/platform/developing). ## Licensing Most of Infisical's code is under the MIT license, though some paid feature restrictions are covered by a proprietary license. Any third party components incorporated into our code are licensed under the original license provided by the applicable component owner. - From 01126ad3fd82e6dd7a4535a37d7630a77193f6eb Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Wed, 22 Oct 2025 22:21:51 +0530 Subject: [PATCH 061/146] fix: greptile review --- docs/contributing/getting-started/overview.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/getting-started/overview.mdx b/docs/contributing/getting-started/overview.mdx index 1d79002a4..396ed8b21 100644 --- a/docs/contributing/getting-started/overview.mdx +++ b/docs/contributing/getting-started/overview.mdx @@ -11,7 +11,7 @@ should approach the development and contribution process. Infisical has two major code-bases. One for the platform code, and one for SDKs. The contribution process has some key differences between the two, so we've split the documentation into two sections: - The [Infisical Platform](https://github.com/Infisical/infisical), the Infisical platform itself. -- The Infisical SDKs, please refer to the each individual SDK documentation for more information. +- The Infisical SDKs, please refer to each individual SDK documentation for more information. - [Node.js SDK](https://github.com/Infisical/node-sdk-v2) - [Python SDK](https://github.com/Infisical/python-sdk-official) - [Java SDK](https://github.com/Infisical/java-sdk) From 5887b64a9e4091aecd48e7a07685e0e5d8d2b87a Mon Sep 17 00:00:00 2001 From: Carlos Monastyrski Date: Wed, 22 Oct 2025 14:35:59 -0300 Subject: [PATCH 062/146] Fix getImportReplicatedFolder function to retrieve only the id part of it --- .../components/SecretImportListView/SecretImportListView.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretImportListView/SecretImportListView.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretImportListView/SecretImportListView.tsx index be492f494..2dbc95020 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretImportListView/SecretImportListView.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretImportListView/SecretImportListView.tsx @@ -130,7 +130,8 @@ export const SecretImportListView = ({ const [items, setItems] = useState(secretImports ?? []); const getImportReplicatedFolder = (importPath: string) => { - const cleanImportPath = importPath.replace("/__reserve_replication_", ""); + if (!importPath.includes("/__reserve_replication_")) return; + const cleanImportPath = importPath.split("/__reserve_replication_")[1]; const replicatedFolder = items?.find(({ id }) => id === cleanImportPath); return replicatedFolder; }; From b4a787e2c90901fe18a6afdc0407a27268781cfd Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Wed, 22 Oct 2025 23:06:32 +0530 Subject: [PATCH 063/146] fix: update SDK documentation references to repositories --- docs/contributing/getting-started/overview.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing/getting-started/overview.mdx b/docs/contributing/getting-started/overview.mdx index 396ed8b21..1784b77e8 100644 --- a/docs/contributing/getting-started/overview.mdx +++ b/docs/contributing/getting-started/overview.mdx @@ -11,7 +11,7 @@ should approach the development and contribution process. Infisical has two major code-bases. One for the platform code, and one for SDKs. The contribution process has some key differences between the two, so we've split the documentation into two sections: - The [Infisical Platform](https://github.com/Infisical/infisical), the Infisical platform itself. -- The Infisical SDKs, please refer to each individual SDK documentation for more information. +- The Infisical SDKs, please refer to each individual SDK repositories for more information. - [Node.js SDK](https://github.com/Infisical/node-sdk-v2) - [Python SDK](https://github.com/Infisical/python-sdk-official) - [Java SDK](https://github.com/Infisical/java-sdk) From df050096886e306d645e94eb7065d5025087ca23 Mon Sep 17 00:00:00 2001 From: Carlos Monastyrski Date: Wed, 22 Oct 2025 14:36:54 -0300 Subject: [PATCH 064/146] Add default return on getImportReplicatedFolder --- .../components/SecretImportListView/SecretImportListView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretImportListView/SecretImportListView.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretImportListView/SecretImportListView.tsx index 2dbc95020..ab4a968d9 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretImportListView/SecretImportListView.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretImportListView/SecretImportListView.tsx @@ -130,7 +130,7 @@ export const SecretImportListView = ({ const [items, setItems] = useState(secretImports ?? []); const getImportReplicatedFolder = (importPath: string) => { - if (!importPath.includes("/__reserve_replication_")) return; + if (!importPath.includes("/__reserve_replication_")) return importPath; const cleanImportPath = importPath.split("/__reserve_replication_")[1]; const replicatedFolder = items?.find(({ id }) => id === cleanImportPath); return replicatedFolder; From 22bff72c2af33fb49c4de757c5cec1e4dbac4c36 Mon Sep 17 00:00:00 2001 From: Carlos Monastyrski Date: Wed, 22 Oct 2025 14:41:43 -0300 Subject: [PATCH 065/146] Add default return on getImportReplicatedFolder --- .../components/SecretImportListView/SecretImportListView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretImportListView/SecretImportListView.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretImportListView/SecretImportListView.tsx index ab4a968d9..763872e9e 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretImportListView/SecretImportListView.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretImportListView/SecretImportListView.tsx @@ -130,7 +130,7 @@ export const SecretImportListView = ({ const [items, setItems] = useState(secretImports ?? []); const getImportReplicatedFolder = (importPath: string) => { - if (!importPath.includes("/__reserve_replication_")) return importPath; + if (!importPath.includes("/__reserve_replication_")) return undefined; const cleanImportPath = importPath.split("/__reserve_replication_")[1]; const replicatedFolder = items?.find(({ id }) => id === cleanImportPath); return replicatedFolder; From 1f5deb9f56a47103bf44dfee1dab87977f54a84e Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Wed, 22 Oct 2025 22:13:49 +0400 Subject: [PATCH 066/146] Update identity-aws-auth-validators.ts --- .../identity-aws-auth/identity-aws-auth-validators.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts index 098bdcf9a..527d508f5 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts @@ -4,7 +4,10 @@ import { z } from "zod"; const twelveDigitRegex = new RE2(/^\d{12}$/); // akhilmhdh: change this to a normal function later. Checked no redosable at the moment -const arnRegex = new RE2(/^arn:aws:iam::\d{12}:(user\/[a-zA-Z0-9_.@+*/-]+|role\/[a-zA-Z0-9_.@+*/-]+|\*)$/); + +const arnRegex = new RE2( + /^arn:aws:iam::\d{12}:(user\/[a-zA-Z0-9_.@+*/-]+|role\/[a-zA-Z0-9_.@+*/-]+|assume-role\/[a-zA-Z0-9_.@+*/-]+|\*)$/ +); export const validateAccountIds = z .string() @@ -52,7 +55,7 @@ export const validatePrincipalArns = z }, { message: - "Each ARN must be in the format of 'arn:aws:iam::123456789012:user/UserName', 'arn:aws:iam::123456789012:role/RoleName', or 'arn:aws:iam::123456789012:*'." + "Each ARN must be in the format of 'arn:aws:iam::123456789012:user/UserName', 'arn:aws:iam::123456789012:role/RoleName', 'arn:aws:iam::123456789012:assume-role/RoleName', or 'arn:aws:iam::123456789012:*'." } ) // Transform to normalize the spaces around commas From 3280cf5e30c2a3f4a7553834bccb5dab9c6b68bb Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Wed, 22 Oct 2025 22:59:24 +0400 Subject: [PATCH 067/146] fix: aws auth STS assume role --- .../src/services/identity-aws-auth/identity-aws-auth-fns.ts | 6 +++--- .../identity-aws-auth/identity-aws-auth-validators.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-fns.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-fns.ts index d0fb4d323..3732cf5c0 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-fns.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-fns.ts @@ -2,7 +2,7 @@ interface PrincipalArnEntity { Partition: string; Service: "iam" | "sts"; AccountNumber: string; - Type: "user" | "role" | "instance-profile"; + Type: "user" | "role" | "instance-profile" | "assumed-role"; Path: string; FriendlyName: string; SessionInfo: string; // Only populated for assumed-role @@ -49,7 +49,7 @@ export const extractPrincipalArnEntity = (arn: string): PrincipalArnEntity => { } // assumed roles use a special format where the friendly name is the role name const [roleName, sessionId] = rest; - finalType = "role"; // treat assumed role case as role + finalType = "assumed-role"; friendlyName = roleName; sessionInfo = sessionId; break; @@ -87,5 +87,5 @@ export const extractPrincipalArnEntity = (arn: string): PrincipalArnEntity => { export const extractPrincipalArn = (arn: string) => { const entity = extractPrincipalArnEntity(arn); - return `arn:aws:iam::${entity.AccountNumber}:${entity.Type}/${entity.FriendlyName}`; + return `arn:aws:${entity.Service}::${entity.AccountNumber}:${entity.Type}/${entity.FriendlyName}${entity.SessionInfo ? `/${entity.SessionInfo}` : ""}`; }; diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts index 527d508f5..183f3cab5 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts @@ -6,7 +6,7 @@ const twelveDigitRegex = new RE2(/^\d{12}$/); // akhilmhdh: change this to a normal function later. Checked no redosable at the moment const arnRegex = new RE2( - /^arn:aws:iam::\d{12}:(user\/[a-zA-Z0-9_.@+*/-]+|role\/[a-zA-Z0-9_.@+*/-]+|assume-role\/[a-zA-Z0-9_.@+*/-]+|\*)$/ + /^arn:aws:(iam|sts)::\d{12}:(user\/[a-zA-Z0-9_.@+*/-]+|role\/[a-zA-Z0-9_.@+*/-]+|assumed-role\/[a-zA-Z0-9_.@+*/-]+\/[a-zA-Z0-9_.@+*/-]+|\*)$/ ); export const validateAccountIds = z @@ -55,7 +55,7 @@ export const validatePrincipalArns = z }, { message: - "Each ARN must be in the format of 'arn:aws:iam::123456789012:user/UserName', 'arn:aws:iam::123456789012:role/RoleName', 'arn:aws:iam::123456789012:assume-role/RoleName', or 'arn:aws:iam::123456789012:*'." + "Each ARN must be in the format of 'arn:aws:iam::123456789012:user/UserName', 'arn:aws:iam::123456789012:role/RoleName', or 'arn:aws:iam::123456789012:*,', 'arn:aws:sts::123456789012:assumed-role/RoleName/sessionId'." } ) // Transform to normalize the spaces around commas From f34964adf7d33d0360b48a9fd33f96d9035fb17b Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Wed, 22 Oct 2025 23:15:25 +0400 Subject: [PATCH 068/146] remove session id extraction --- .../src/services/identity-aws-auth/identity-aws-auth-fns.ts | 2 +- .../identity-aws-auth/identity-aws-auth-validators.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-fns.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-fns.ts index 3732cf5c0..c8b494e7b 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-fns.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-fns.ts @@ -87,5 +87,5 @@ export const extractPrincipalArnEntity = (arn: string): PrincipalArnEntity => { export const extractPrincipalArn = (arn: string) => { const entity = extractPrincipalArnEntity(arn); - return `arn:aws:${entity.Service}::${entity.AccountNumber}:${entity.Type}/${entity.FriendlyName}${entity.SessionInfo ? `/${entity.SessionInfo}` : ""}`; + return `arn:aws:${entity.Service}::${entity.AccountNumber}:${entity.Type}/${entity.FriendlyName}`; }; diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts index 183f3cab5..fa2432408 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts @@ -6,7 +6,7 @@ const twelveDigitRegex = new RE2(/^\d{12}$/); // akhilmhdh: change this to a normal function later. Checked no redosable at the moment const arnRegex = new RE2( - /^arn:aws:(iam|sts)::\d{12}:(user\/[a-zA-Z0-9_.@+*/-]+|role\/[a-zA-Z0-9_.@+*/-]+|assumed-role\/[a-zA-Z0-9_.@+*/-]+\/[a-zA-Z0-9_.@+*/-]+|\*)$/ + /^arn:aws:(iam|sts)::\d{12}:(user\/[a-zA-Z0-9_.@+*/-]+|role\/[a-zA-Z0-9_.@+*/-]+|assumed-role\/[a-zA-Z0-9_.@+*/-]+|\*)$/ ); export const validateAccountIds = z @@ -55,7 +55,7 @@ export const validatePrincipalArns = z }, { message: - "Each ARN must be in the format of 'arn:aws:iam::123456789012:user/UserName', 'arn:aws:iam::123456789012:role/RoleName', or 'arn:aws:iam::123456789012:*,', 'arn:aws:sts::123456789012:assumed-role/RoleName/sessionId'." + "Each ARN must be in the format of 'arn:aws:iam::123456789012:user/UserName', 'arn:aws:iam::123456789012:role/RoleName', or 'arn:aws:iam::123456789012:*,', 'arn:aws:sts::123456789012:assumed-role/RoleName'." } ) // Transform to normalize the spaces around commas From d04854e07600794efa8c9beafade44a7b76e4f1f Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Wed, 22 Oct 2025 23:23:02 +0400 Subject: [PATCH 069/146] Update identity-aws-auth-validators.ts --- .../services/identity-aws-auth/identity-aws-auth-validators.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts index fa2432408..4e3884e15 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts @@ -55,7 +55,7 @@ export const validatePrincipalArns = z }, { message: - "Each ARN must be in the format of 'arn:aws:iam::123456789012:user/UserName', 'arn:aws:iam::123456789012:role/RoleName', or 'arn:aws:iam::123456789012:*,', 'arn:aws:sts::123456789012:assumed-role/RoleName'." + "Each ARN must be in the format of 'arn:aws:iam::123456789012:user/UserName', 'arn:aws:iam::123456789012:role/RoleName', or 'arn:aws:iam::123456789012:*', 'arn:aws:sts::123456789012:assumed-role/RoleName'." } ) // Transform to normalize the spaces around commas From 4a7f4e101b46116c42f72c922bf4c3a2d5f449ec Mon Sep 17 00:00:00 2001 From: x032205 Date: Wed, 22 Oct 2025 19:22:49 -0400 Subject: [PATCH 070/146] some review changes --- .../components/GatewayCliDeploymentMethod.tsx | 10 +- .../GatewayDeploymentMethodSelect.tsx | 2 +- .../components/RelayCliDeploymentMethod.tsx | 202 ++++++++++++------ .../RelayDeploymentMethodSelect.tsx | 2 +- 4 files changed, 141 insertions(+), 75 deletions(-) diff --git a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayCliDeploymentMethod.tsx b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayCliDeploymentMethod.tsx index a98853bbb..87ca2deee 100644 --- a/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayCliDeploymentMethod.tsx +++ b/frontend/src/pages/organization/NetworkingPage/components/GatewayTab/components/GatewayCliDeploymentMethod.tsx @@ -208,7 +208,7 @@ export const GatewayCliDeploymentMethod = () => { placeholder="Enter gateway name..." isError={Boolean(errors.name)} /> - {errors.name &&

{errors.name}

} + {errors.name &&

{errors.name}

} { getOptionValue={(option) => option.id} components={{ Option: RelayOption }} /> - {errors.relay &&

{errors.relay}

} + {errors.relay &&

{errors.relay}

} { placeholder="https://app.infisical.com" isError={Boolean(errors.instanceDomain)} /> - {errors.instanceDomain && ( -

{errors.instanceDomain}

- )} + {errors.instanceDomain &&

{errors.instanceDomain}

} { getOptionValue={(option) => option.id} getOptionLabel={(option) => option.name} /> - {errors.identity &&

{errors.identity}

} + {errors.identity &&

{errors.identity}

}
+

+ {errors.identity &&

{errors.identity}

} + + ) : ( + <> + + setIdentityToken(e.target.value)} + placeholder="Enter identity token..." + isError={Boolean(errors.identityToken)} + /> + {canCreateToken && ( + + )} + {errors.identityToken &&

{errors.identityToken}

} + + )}
-

{errors.identity &&

{errors.identity}

} ) : ( @@ -303,18 +295,42 @@ export const RelayCliDeploymentMethod = () => { placeholder="Enter identity token..." isError={Boolean(errors.identityToken)} /> - {canCreateToken && ( - - )} {errors.identityToken &&

{errors.identityToken}

} )} + {canCreateToken && ( +
+ { + setAutogenerateToken(Boolean(e)); + }} + id="autogenerate-token" + className="mr-2" + > +
+ Automatically enable token auth and generate a token for identity + + Token authentication will be automatically enabled for the selected identity if + it isn't already configured. By default, it will be configured to allow all IP + addresses with a token TTL of 30 days. You can manage these settings in Access + Control. +
+
A token will automatically be generated to be used with the CLI command. + + } + > + +
+
+
+
+ )} +
+ +
+ + )} + + {/* Show edit form for enabled auto-renewal without errors */} + {isAutoRenewalEnabled && !hasRenewalError && ( +
+ + ( + { + const value = parseInt(e.target.value, 10); + field.onChange(value); + }} + placeholder="Enter days before expiration" + /> + )} + /> + + +
+ + +
+
+ )} + + + ); +}; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRenewalConfigModal.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRenewalConfigModal.tsx new file mode 100644 index 000000000..1c195dd22 --- /dev/null +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRenewalConfigModal.tsx @@ -0,0 +1,177 @@ +import { Controller, useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; + +import { createNotification } from "@app/components/notifications"; +import { Button, FormControl, Input, Modal, ModalContent } from "@app/components/v2"; +import { useProject } from "@app/context"; +import { useUpdateRenewalConfig } from "@app/hooks/api"; +import { UsePopUpState } from "@app/hooks/usePopUp"; + +const formSchema = z.object({ + renewBeforeDays: z + .number() + .min(1, "Renewal days must be at least 1") + .max(365, "Renewal days cannot exceed 365") +}); + +type FormData = z.infer; + +type Props = { + popUp: UsePopUpState<["configureRenewal"]>; + handlePopUpToggle: ( + popUpName: keyof UsePopUpState<["configureRenewal"]>, + state?: boolean + ) => void; +}; + +export const CertificateRenewalConfigModal = ({ popUp, handlePopUpToggle }: Props) => { + const { currentProject } = useProject(); + const { mutateAsync: updateRenewalConfig, isPending: isSubmitting } = useUpdateRenewalConfig(); + + const certificateData = popUp.configureRenewal.data as { + certificateId: string; + commonName: string; + profileId: string; + renewBeforeDays?: number; + ttlDays: number; + }; + + const { + control, + handleSubmit, + formState: { errors }, + watch + } = useForm({ + resolver: zodResolver(formSchema), + defaultValues: { + renewBeforeDays: certificateData?.renewBeforeDays || 7 + } + }); + + const renewBeforeDays = watch("renewBeforeDays"); + + const onSubmit = async (data: FormData) => { + try { + if (data.renewBeforeDays >= certificateData.ttlDays) { + createNotification({ + text: `Renewal days (${data.renewBeforeDays}) must be less than certificate TTL (${certificateData.ttlDays} days)`, + type: "error" + }); + return; + } + + if (!currentProject?.slug) { + createNotification({ + text: "Project not found", + type: "error" + }); + return; + } + + await updateRenewalConfig({ + certificateId: certificateData.certificateId, + renewBeforeDays: data.renewBeforeDays, + projectSlug: currentProject.slug + }); + + createNotification({ + text: "Successfully updated auto-renewal configuration", + type: "success" + }); + + handlePopUpToggle("configureRenewal", false); + } catch (err) { + console.error(err); + createNotification({ + text: "Failed to update auto-renewal configuration", + type: "error" + }); + } + }; + + return ( + { + handlePopUpToggle("configureRenewal", isOpen); + }} + > + +
+
+

+ Configure when this certificate should be automatically renewed. The certificate will + be renewed when it has the specified number of days remaining before expiration. +

+ +
+

+ Certificate TTL: {certificateData?.ttlDays} days +

+

+ Current Setting:{" "} + {certificateData?.renewBeforeDays + ? `${certificateData.renewBeforeDays} days before expiration` + : "Disabled"} +

+
+ + ( + + { + const value = parseInt(e.target.value, 10); + field.onChange(Number.isNaN(value) ? 0 : value); + }} + /> + + )} + /> + + {renewBeforeDays && certificateData?.ttlDays && ( +
+

+ {renewBeforeDays >= (certificateData.ttlDays || 0) + ? "⚠️ Renewal days must be less than certificate TTL" + : `✓ Certificate will be renewed ${renewBeforeDays} days before expiration`} +

+
+ )} +
+ +
+ + +
+
+
+
+ ); +}; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRenewalDisableModal.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRenewalDisableModal.tsx new file mode 100644 index 000000000..619272041 --- /dev/null +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRenewalDisableModal.tsx @@ -0,0 +1,94 @@ +import { createNotification } from "@app/components/notifications"; +import { Button, Modal, ModalContent } from "@app/components/v2"; +import { useProject } from "@app/context"; +import { useUpdateRenewalConfig } from "@app/hooks/api"; +import { UsePopUpState } from "@app/hooks/usePopUp"; + +type Props = { + popUp: UsePopUpState<["disableRenewal"]>; + handlePopUpToggle: (popUpName: keyof UsePopUpState<["disableRenewal"]>, state?: boolean) => void; +}; + +export const CertificateRenewalDisableModal = ({ popUp, handlePopUpToggle }: Props) => { + const { currentProject } = useProject(); + const { mutateAsync: updateRenewalConfig, isPending: isSubmitting } = useUpdateRenewalConfig(); + + const certificateData = popUp.disableRenewal.data as { + certificateId: string; + commonName: string; + }; + + const onDisableConfirm = async () => { + try { + if (!currentProject?.slug) { + createNotification({ + text: "Project not found", + type: "error" + }); + return; + } + + await updateRenewalConfig({ + certificateId: certificateData.certificateId, + projectSlug: currentProject.slug, + disableAutoRenewal: true + }); + + createNotification({ + text: "Successfully disabled auto-renewal", + type: "success" + }); + + handlePopUpToggle("disableRenewal", false); + } catch (err) { + console.error(err); + createNotification({ + text: "Failed to disable auto-renewal", + type: "error" + }); + } + }; + + return ( + { + handlePopUpToggle("disableRenewal", isOpen); + }} + > + +
+

+ Are you sure you want to disable auto-renewal for this certificate? +

+
+

+ Warning: Once disabled, this certificate will not be automatically + renewed and may expire without notice. You can re-enable auto-renewal at any time. +

+
+
+ +
+ + +
+
+
+ ); +}; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRenewalModal.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRenewalModal.tsx new file mode 100644 index 000000000..0e2b1c17d --- /dev/null +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRenewalModal.tsx @@ -0,0 +1,80 @@ +import { faRedo } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +import { createNotification } from "@app/components/notifications"; +import { Button, Modal, ModalContent } from "@app/components/v2"; +import { useRenewCertificate } from "@app/hooks/api"; +import { UsePopUpState } from "@app/hooks/usePopUp"; + +type Props = { + popUp: UsePopUpState<["renewCertificate"]>; + handlePopUpToggle: ( + popUpName: keyof UsePopUpState<["renewCertificate"]>, + state?: boolean + ) => void; +}; + +export const CertificateRenewalModal = ({ popUp, handlePopUpToggle }: Props) => { + const { mutateAsync: renewCertificate, isPending: isRenewing } = useRenewCertificate(); + + const onRenewConfirm = async () => { + try { + const { certificateId } = popUp.renewCertificate.data as { certificateId: string }; + + await renewCertificate({ + certificateId + }); + + createNotification({ + text: "Certificate renewed successfully", + type: "success" + }); + + handlePopUpToggle("renewCertificate", false); + } catch (err) { + console.error(err); + } + }; + + const certificateData = popUp.renewCertificate.data as { + certificateId: string; + commonName: string; + profileId: string; + }; + + return ( + { + handlePopUpToggle("renewCertificate", isOpen); + }} + > + +
+

+ Are you sure you want to renew this certificate now? +

+
+ +
+ + +
+
+
+ ); +}; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesSection.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesSection.tsx index bce21123b..4102d8ea5 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesSection.tsx +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesSection.tsx @@ -16,7 +16,9 @@ import { usePopUp } from "@app/hooks/usePopUp"; import { CertificateCertModal } from "./CertificateCertModal"; import { CertificateImportModal } from "./CertificateImportModal"; import { CertificateIssuanceModal } from "./CertificateIssuanceModal"; +import { CertificateManageRenewalModal } from "./CertificateManageRenewalModal"; import { CertificateModal } from "./CertificateModal"; +import { CertificateRenewalModal } from "./CertificateRenewalModal"; import { CertificateRevocationModal } from "./CertificateRevocationModal"; import { CertificatesTable } from "./CertificatesTable"; @@ -33,7 +35,9 @@ export const CertificatesSection = () => { "certificateImport", "certificateCert", "deleteCertificate", - "revokeCertificate" + "revokeCertificate", + "manageRenewal", + "renewCertificate" ] as const); const onRemoveCertificateSubmit = async (serialNumber: string) => { @@ -98,6 +102,8 @@ export const CertificatesSection = () => { )} + + { + const expiryDate = new Date(notAfter); + const now = new Date(); + const oneDayFromNow = new Date(now.getTime() + 24 * 60 * 60 * 1000); + return expiryDate <= oneDayFromNow; +}; + +const getAutoRenewalInfo = (certificate: TCertificate) => { + if (certificate.renewedById) { + return { text: "Renewed", variant: "success" as const }; + } + + const isRevoked = certificate.status === CertStatus.REVOKED; + const isExpired = new Date(certificate.notAfter) < new Date(); + const hasNoProfile = !certificate.profileId; + const isExpiringWithinDay = isExpiringWithinOneDay(certificate.notAfter); + + if (isRevoked || isExpired || hasNoProfile || isExpiringWithinDay) { + return null; + } + + if (certificate.renewalError) { + return { + text: "Failed", + variant: "danger" as const, + tooltip: certificate.renewalError + }; + } + + if (!certificate.renewBeforeDays) { + return { text: "Disabled", variant: "primary" as const }; + } + + const notAfterDate = new Date(certificate.notAfter); + const renewalDate = new Date( + notAfterDate.getTime() - certificate.renewBeforeDays * 24 * 60 * 60 * 1000 + ); + const now = new Date(); + + if (renewalDate <= now) { + return { text: "Due Now", variant: "danger" as const }; + } + + const daysUntilRenewal = Math.ceil( + (renewalDate.getTime() - now.getTime()) / (24 * 60 * 60 * 1000) + ); + + if (daysUntilRenewal <= 7) { + return { text: `Renews in ${daysUntilRenewal}d`, variant: "primary" as const }; + } + + return { text: `Renews in ${daysUntilRenewal}d`, variant: "success" as const }; +}; + type Props = { handlePopUpOpen: ( popUpName: keyof UsePopUpState< - ["certificate", "deleteCertificate", "revokeCertificate", "certificateCert"] + [ + "certificate", + "deleteCertificate", + "revokeCertificate", + "certificateCert", + "manageRenewal", + "renewCertificate" + ] >, data?: { serialNumber?: string; commonName?: string; + certificateId?: string; + profileId?: string; + renewBeforeDays?: number; + ttlDays?: number; + notAfter?: string; + renewalError?: string; + renewedFromId?: string; + renewedById?: string; } ) => void; }; @@ -69,10 +142,10 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { limit: perPage }); - // Fetch CA data to determine capabilities + const { mutateAsync: updateRenewalConfig } = useUpdateRenewalConfig(); + const { data: caData } = useListCasByProjectId(currentProject?.id ?? ""); - // Create mapping from caId to CA type for capability checking const caCapabilityMap = useMemo(() => { if (!caData) return {}; @@ -83,6 +156,35 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { return map; }, [caData]); + const handleDisableAutoRenewal = async (certificateId: string, commonName: string) => { + try { + if (!currentProject?.slug) { + createNotification({ + text: "Unable to disable auto-renewal: Project not found. Please refresh the page and try again.", + type: "error" + }); + return; + } + + await updateRenewalConfig({ + certificateId, + projectSlug: currentProject.slug, + disableAutoRenewal: true + }); + + createNotification({ + text: `Auto-renewal disabled for ${commonName}`, + type: "success" + }); + } catch (err) { + console.error(err); + createNotification({ + text: "Failed to disable auto-renewal. Please try again or contact support if the issue persists.", + type: "error" + }); + } + }; + return ( @@ -92,14 +194,16 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { + - {isPending && } + {isPending && } {!isPending && data?.certificates.map((certificate) => { const { variant, label } = getCertValidUntilBadgeDetails(certificate.notAfter); + const autoRenewalInfo = getAutoRenewalInfo(certificate); return ( @@ -120,6 +224,25 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { ? format(new Date(certificate.notAfter), "yyyy-MM-dd") : "-"} + @@ -297,10 +309,6 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { {/* Manage auto renewal option - not shown for failed renewals */} {(() => { - const isRevoked = certificate.status === CertStatus.REVOKED; - const isExpired = new Date(certificate.notAfter) < new Date(); - const hasFailed = Boolean(certificate.renewalError); - const isExpiringWithinDay = isExpiringWithinOneDay(certificate.notAfter); const canManageRenewal = certificate.profileId && !certificate.renewedById && @@ -317,10 +325,6 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { a={ProjectPermissionSub.Certificates} > {(isAllowed) => { - const isAutoRenewalEnabled = Boolean( - certificate.renewBeforeDays && certificate.renewBeforeDays > 0 - ); - return ( { )} onClick={async () => { const notAfterDate = new Date(certificate.notAfter); - const notBeforeDate = new Date(certificate.notBefore); - const ttlDays = Math.ceil( - (notAfterDate.getTime() - notBeforeDate.getTime()) / - (24 * 60 * 60 * 1000) + const notBeforeDate = certificate.notBefore + ? new Date(certificate.notBefore) + : new Date( + notAfterDate.getTime() - 365 * 24 * 60 * 60 * 1000 + ); + const ttlDays = Math.max( + 1, + Math.ceil( + (notAfterDate.getTime() - notBeforeDate.getTime()) / + (24 * 60 * 60 * 1000) + ) ); handlePopUpOpen("manageRenewal", { certificateId: certificate.id, @@ -360,12 +371,6 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { })()} {/* Disable auto renewal option - only shown when auto renewal is active */} {(() => { - const isRevoked = certificate.status === CertStatus.REVOKED; - const isExpired = new Date(certificate.notAfter) < new Date(); - const isExpiringWithinDay = isExpiringWithinOneDay(certificate.notAfter); - const isAutoRenewalEnabled = Boolean( - certificate.renewBeforeDays && certificate.renewBeforeDays > 0 - ); const canDisableRenewal = certificate.profileId && !certificate.renewedById && @@ -404,8 +409,6 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { })()} {/* Manual renewal action for profile-issued certificates that are not revoked/expired (including failed ones) */} {(() => { - const isRevoked = certificate.status === CertStatus.REVOKED; - const isExpired = new Date(certificate.notAfter) < new Date(); const canRenew = certificate.profileId && !certificate.renewedById && From 3ebd6283630db7638698d29eca9135c306665c55 Mon Sep 17 00:00:00 2001 From: Victor Santos Date: Thu, 23 Oct 2025 11:20:30 -0300 Subject: [PATCH 083/146] docs: update login command documentation to include organization-id parameter for direct login --- docs/cli/commands/login.mdx | 52 +++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/docs/cli/commands/login.mdx b/docs/cli/commands/login.mdx index 1f7a08350..c58c13713 100644 --- a/docs/cli/commands/login.mdx +++ b/docs/cli/commands/login.mdx @@ -49,10 +49,13 @@ User authentication is designed for individual developers and supports multiple - Your email address. Required for direct login along with `--password`. + Your email address. Required for direct login along with `--password` and `--organization-id`. - Your password. Required for direct login along with `--email`. + Your password. Required for direct login along with `--email` and `--organization-id`. + + + Your organization id. Required for direct login along with `--password` and `--email`. Force interactive CLI login instead of browser-based authentication. @@ -71,11 +74,12 @@ User authentication is designed for individual developers and supports multiple ```bash - infisical login --email=user@example.com --password=your-password + infisical login --email=user@example.com --password=your-password --organization-id=your-organization-id # Or using environment variables export INFISICAL_EMAIL="user@example.com" export INFISICAL_PASSWORD="your-password" + export INFISICAL_ORGANIZATION_ID="your-organization-id" infisical login ``` @@ -86,7 +90,7 @@ User authentication is designed for individual developers and supports multiple ```bash - export INFISICAL_TOKEN=$(infisical login --email=user@example.com --password=your-password --plain --silent) + export INFISICAL_TOKEN=$(infisical login --email=user@example.com --password=your-password --organization-id=your-organization-id --plain --silent) ``` @@ -404,11 +408,11 @@ The login command supports a number of flags that you can use for different auth ```bash - infisical login --email= --password= + infisical login --email= --password= --organization-id= ``` #### Description - User email address. Required if you want to do a non-interactive login when the **--method** flag is set to **user**. Must be used together with the `--password` flag. + User email address. Required if you want to do a non-interactive login when the **--method** flag is set to **user**. Must be used together with the `--password` and `--organization-id` flag. You can omit the **--method=user** if you want as it's the default method. @@ -421,11 +425,11 @@ The login command supports a number of flags that you can use for different auth ```bash - infisical login --email= --password= + infisical login --email= --password= --organization-id= ``` #### Description - User password. Required if you want to do a non-interactive login when the **--method** flag is set to **user**. Must be used together with the `--email` flag. + User password. Required if you want to do a non-interactive login when the **--method** flag is set to **user**. Must be used together with the `--email` and `--organization-id` flag. For security in CI/CD environments, prefer using the `INFISICAL_PASSWORD` environment variable instead of passing the password as a command-line flag. @@ -439,6 +443,23 @@ The login command supports a number of flags that you can use for different auth The `password` flag can be substituted with the `INFISICAL_PASSWORD` environment variable. + + + ```bash + infisical login --email= --password= --organization-id= + ``` + + #### Description + User organization id. Required if you want to do a non-interactive login when the **--method** flag is set to **user**. Must be used together with the `--email` and `--password` flag. + + + You can omit the **--method=user** if you want as it's the default method. + + + + The `organization-id` flag can be substituted with the `INFISICAL_ORGANIZATION_ID` environment variable. + + ```bash @@ -446,12 +467,12 @@ The login command supports a number of flags that you can use for different auth ``` #### Description - Forces interactive CLI login where you'll be prompted to enter your email and password in the terminal, instead of opening a browser. + Forces interactive CLI login where you'll be prompted to enter your email, password, and select your organization in the terminal, instead of opening a browser. ```bash - infisical login --email= --password= --plain + infisical login --email= --password= --organization-id= --plain ``` #### Description @@ -459,7 +480,7 @@ The login command supports a number of flags that you can use for different auth ```bash # Example: Capture token in a variable - export INFISICAL_TOKEN=$(infisical login --email= --password= --plain --silent) + export INFISICAL_TOKEN=$(infisical login --email= --password= --organization-id= --plain --silent) ``` @@ -506,13 +527,13 @@ The following examples demonstrate different ways to authenticate as a user with ```bash # Basic direct login (defaults to US Cloud) - infisical login --email user@example.com --password "your-password" + infisical login --email user@example.com --password "your-password" --organization-id "your-organization-id" # EU Cloud (Custom domain) - infisical login --email user@example.com --password "your-password" --domain https://eu.infisical.com + infisical login --email user@example.com --password "your-password" --organization-id "your-organization-id" --domain https://eu.infisical.com # Output only JWT token for scripting - export INFISICAL_TOKEN=$(infisical login --email user@example.com --password "your-password" --plain --silent) + export INFISICAL_TOKEN=$(infisical login --email user@example.com --password "your-password" --organization-id "your-organization-id" --plain --silent) ``` #### Using Environment Variables (Recommended for CI/CD) @@ -521,6 +542,7 @@ The following examples demonstrate different ways to authenticate as a user with # Set credentials as environment variables export INFISICAL_EMAIL="user@example.com" export INFISICAL_PASSWORD="your-password" + export INFISICAL_ORGANIZATION_ID="your-organization-id" # Login without additional flags infisical login @@ -542,6 +564,8 @@ The following examples demonstrate different ways to authenticate as a user with - Email address - Password + After the prompt, you will be shown a list of organizations to choose from. + From 666a09b86b165f36451fb850548f1b87978662f6 Mon Sep 17 00:00:00 2001 From: Carlos Monastyrski Date: Thu, 23 Oct 2025 12:52:17 -0300 Subject: [PATCH 084/146] Fix missing membership from SAML mapped groups --- ...023121055_fix-missing-group-memberships.ts | 45 +++++++++++++++++++ .../saml-config/saml-config-service.ts | 10 ++++- 2 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 backend/src/db/migrations/20251023121055_fix-missing-group-memberships.ts diff --git a/backend/src/db/migrations/20251023121055_fix-missing-group-memberships.ts b/backend/src/db/migrations/20251023121055_fix-missing-group-memberships.ts new file mode 100644 index 000000000..e4af23c46 --- /dev/null +++ b/backend/src/db/migrations/20251023121055_fix-missing-group-memberships.ts @@ -0,0 +1,45 @@ +import { Knex } from "knex"; + +import { AccessScope, TableName } from "../schemas"; + +export async function up(knex: Knex): Promise { + const hasGroupsTable = await knex.schema.hasTable(TableName.Groups); + const hasMembershipTable = await knex.schema.hasTable(TableName.Membership); + + if (!hasGroupsTable || !hasMembershipTable) { + return; + } + + const groupsWithoutMembership = await knex + .select(`${TableName.Groups}.id`, `${TableName.Groups}.orgId`) + .from(TableName.Groups) + .leftJoin(TableName.Membership, function joinGroupMembership() { + this.on(`${TableName.Groups}.id`, "=", `${TableName.Membership}.actorGroupId`); + }) + .whereNull(`${TableName.Membership}.actorGroupId`); + + if (groupsWithoutMembership.length > 0) { + const membershipInserts = groupsWithoutMembership.map((group) => ({ + actorGroupId: group.id, + scope: AccessScope.Organization, + scopeOrgId: group.orgId, + isActive: true + })); + + await knex(TableName.Membership).insert(membershipInserts); + } + + await knex.schema.alterTable(TableName.Membership, (t) => { + t.check( + `("actorUserId" IS NOT NULL OR "actorIdentityId" IS NOT NULL OR "actorGroupId" IS NOT NULL)`, + undefined, + "at_least_one_actor" + ); + }); +} + +export async function down(knex: Knex): Promise { + await knex.schema.alterTable(TableName.Membership, (t) => { + t.dropChecks("at_least_one_actor"); + }); +} diff --git a/backend/src/ee/services/saml-config/saml-config-service.ts b/backend/src/ee/services/saml-config/saml-config-service.ts index 13b862343..f9c97fc6f 100644 --- a/backend/src/ee/services/saml-config/saml-config-service.ts +++ b/backend/src/ee/services/saml-config/saml-config-service.ts @@ -84,7 +84,7 @@ type TSamlConfigServiceFactoryDep = { projectDAL: Pick; projectBotDAL: Pick; projectKeyDAL: Pick; - membershipGroupDAL: Pick; + membershipGroupDAL: Pick; }; export const samlConfigServiceFactory = ({ @@ -183,6 +183,14 @@ export const samlConfigServiceFactory = ({ transaction ); orgGroupsMap.set(groupName, newGroup); + await membershipGroupDAL.create( + { + actorGroupId: newGroup.id, + scope: AccessScope.Organization, + scopeOrgId: orgId + }, + transaction + ); } } From fc0d66c1597c7f571057a0441dd2829e51c36f84 Mon Sep 17 00:00:00 2001 From: x032205 Date: Thu, 23 Oct 2025 12:22:45 -0400 Subject: [PATCH 085/146] swap CLI page to overview --- docs/docs.json | 2 +- .../relay-deployment/{cli.mdx => overview.mdx} | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) rename docs/documentation/platform/gateways/relay-deployment/{cli.mdx => overview.mdx} (95%) diff --git a/docs/docs.json b/docs/docs.json index 3bcc8ed89..e702f249d 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -179,7 +179,7 @@ { "group": "Relay Deployment", "pages": [ - "documentation/platform/gateways/relay-deployment/cli", + "documentation/platform/gateways/relay-deployment/overview", "documentation/platform/gateways/relay-deployment/terraform" ] }, diff --git a/docs/documentation/platform/gateways/relay-deployment/cli.mdx b/docs/documentation/platform/gateways/relay-deployment/overview.mdx similarity index 95% rename from docs/documentation/platform/gateways/relay-deployment/cli.mdx rename to docs/documentation/platform/gateways/relay-deployment/overview.mdx index 5c16091a7..ba7689196 100644 --- a/docs/documentation/platform/gateways/relay-deployment/cli.mdx +++ b/docs/documentation/platform/gateways/relay-deployment/overview.mdx @@ -1,6 +1,6 @@ --- -title: "CLI" -description: "How to deploy Infisical Relay Servers using the CLI" +title: "Overview" +description: "How to deploy Infisical Relay Servers" --- Infisical Relay is a secure routing layer that allows Infisical to connect to your private network resources, such as databases or internal APIs, without exposing them to the public internet. @@ -107,13 +107,8 @@ To successfully deploy an Infisical Relay for use, follow these steps in order. - - Install the Infisical CLI on the server where you plan to deploy the relay. The CLI is required for relay installation and management. - - See the [CLI Installation Guide](/cli/overview) for instructions. - - This server must have a static IP address or DNS name to be identifiable by the Infisical platform. - + + Provision a server or virtual machine where you plan to deploy the relay. This server must have a static IP address or DNS name to be identifiable by the Infisical platform. @@ -133,6 +128,8 @@ To successfully deploy an Infisical Relay for use, follow these steps in order. + You can deploy the Infisical Relay in various ways. This guide provides a manual setup example using the Infisical CLI. For an infrastructure-as-code approach, see our [Terraform guide](/documentation/platform/gateways/relay-deployment/terraform). + The Infisical CLI is used to install and start the relay in your chosen environment. The CLI provides commands for both production and development scenarios, and supports a variety of options/flags to configure your deployment. To view all available flags and equivalent environment variables for relay deployment, see the [Relay CLI Command Reference](/cli/commands/relay). From 9a8511acfb187056198110488ea14c6495ee12a9 Mon Sep 17 00:00:00 2001 From: x032205 Date: Thu, 23 Oct 2025 12:28:00 -0400 Subject: [PATCH 086/146] removed deprecated gateway docs --- docs/docs.json | 10 +- .../gateways-deprecated/gateway-security.mdx | 91 ----- .../images/gateway-highlevel-diagram.png | Bin 332077 -> 0 bytes .../gateways-deprecated/networking.mdx | 170 --------- .../platform/gateways-deprecated/overview.mdx | 352 ------------------ 5 files changed, 1 insertion(+), 622 deletions(-) delete mode 100644 docs/documentation/platform/gateways-deprecated/gateway-security.mdx delete mode 100644 docs/documentation/platform/gateways-deprecated/images/gateway-highlevel-diagram.png delete mode 100644 docs/documentation/platform/gateways-deprecated/networking.mdx delete mode 100644 docs/documentation/platform/gateways-deprecated/overview.mdx diff --git a/docs/docs.json b/docs/docs.json index e702f249d..dda9adcfc 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -183,15 +183,7 @@ "documentation/platform/gateways/relay-deployment/terraform" ] }, - "documentation/platform/gateways/security", - { - "group": "Gateway (Deprecated)", - "pages": [ - "documentation/platform/gateways-deprecated/overview", - "documentation/platform/gateways-deprecated/gateway-security", - "documentation/platform/gateways-deprecated/networking" - ] - } + "documentation/platform/gateways/security" ] } ] diff --git a/docs/documentation/platform/gateways-deprecated/gateway-security.mdx b/docs/documentation/platform/gateways-deprecated/gateway-security.mdx deleted file mode 100644 index 93a7f662f..000000000 --- a/docs/documentation/platform/gateways-deprecated/gateway-security.mdx +++ /dev/null @@ -1,91 +0,0 @@ ---- -title: "Gateway Security Architecture" -sidebarTitle: "Architecture" -description: "Understand the security model and tenant isolation of Infisical's Gateway" ---- - -# Gateway Security Architecture - -The Infisical Gateway enables Infisical Cloud to securely interact with private resources using mutual TLS authentication and private PKI (Public Key Infrastructure) system to ensure secure, isolated communication between multiple tenants. -This document explains the internal security architecture and how tenant isolation is maintained. - -## Security Model Overview - -### Private PKI System -Each organization (tenant) in Infisical has its own private PKI system consisting of: - -1. **Root CA**: The ultimate trust anchor for the organization -2. **Intermediate CAs**: - - Client CA: Issues certificates for cloud components - - Gateway CA: Issues certificates for gateway instances - -This hierarchical structure ensures complete isolation between organizations as each has its own independent certificate chain. - -### Certificate Hierarchy -``` -Root CA (Organization Specific) -├── Client CA -│ └── Client Certificates (Cloud Components) -└── Gateway CA - └── Gateway Certificates (Gateway Instances) -``` - -## Communication Security - -### 1. Gateway Registration -When a gateway is first deployed: - -1. Establishes initial connection using machine identity token -2. Allocates a relay address for communication -3. Exchanges certificates through a secure handshake: - - Gateway receives a unique certificate signed by organization's Gateway CA along with certificate chain for verification - -### 2. Mutual TLS Authentication -All communication between gateway and cloud uses mutual TLS (mTLS): - -- **Gateway Authentication**: - - Presents certificate signed by organization's Gateway CA - - Certificate contains unique identifiers (Organization ID, Gateway ID) - - Cloud validates complete certificate chain - -- **Cloud Authentication**: - - Presents certificate signed by organization's Client CA - - Certificate includes required organizational unit ("gateway-client") - - Gateway validates certificate chain back to organization's root CA - -### 3. Relay Communication -The relay system provides secure tunneling: - -1. **Connection Establishment**: - - Uses QUIC protocol over UDP for efficient, secure communication - - Provides built-in encryption, congestion control, and multiplexing - - Enables faster connection establishment and reduced latency - - Each organization's traffic is isolated using separate relay sessions - -2. **Traffic Isolation**: - - Each gateway gets unique relay credentials - - Traffic is end-to-end encrypted using QUIC's TLS 1.3 - - Organization's private keys never leave their environment - -## Tenant Isolation - -### Certificate-Based Isolation -- Each organization has unique root CA and intermediate CAs -- Certificates contain organization-specific identifiers -- Cross-tenant communication is cryptographically impossible - -### Gateway-Project Mapping -- Gateways are explicitly mapped to specific projects -- Access controls enforce organization boundaries -- Project-level permissions determine resource accessibility - -### Resource Access Control -1. **Project Verification**: - - Gateway verifies project membership - - Validates organization ownership - - Enforces project-level permissions - -2. **Resource Restrictions**: - - Gateways only accept connections to approved resources - - Each connection requires explicit project authorization - - Resources remain private to their assigned organization diff --git a/docs/documentation/platform/gateways-deprecated/images/gateway-highlevel-diagram.png b/docs/documentation/platform/gateways-deprecated/images/gateway-highlevel-diagram.png deleted file mode 100644 index 5f942bcf0c3049587e4dd117e5b337cecc1d803e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 332077 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

Vl7cl*;1 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 diff --git a/docs/documentation/platform/gateways-deprecated/networking.mdx b/docs/documentation/platform/gateways-deprecated/networking.mdx deleted file mode 100644 index 51a81ee42..000000000 --- a/docs/documentation/platform/gateways-deprecated/networking.mdx +++ /dev/null @@ -1,170 +0,0 @@ ---- -title: "Networking" -description: "Network configuration and firewall requirements for Infisical Gateway" ---- - -The Infisical Gateway requires outbound network connectivity to establish secure communication with Infisical's relay infrastructure. -This page outlines the required ports, protocols, and firewall configurations needed for optimal gateway usage. - -## Network Architecture - -The gateway uses a relay-based architecture to establish secure connections: - -1. **Gateway** connects outbound to **Relay Servers** using UDP/QUIC protocol -2. **Relay Servers** facilitate secure communication between Gateway and Infisical Cloud -3. All traffic is end-to-end encrypted using mutual TLS over QUIC - -## Required Network Connectivity - -### Outbound Connections (Required) - -The gateway requires the following outbound connectivity: - -| Protocol | Destination | Ports | Purpose | -|----------|-------------|-------|---------| -| UDP | Relay Servers | 49152-65535 | Allocated relay communication (TLS) | -| TCP | app.infisical.com / eu.infisical.com | 443 | API communication and relay allocation | - -### Relay Server IP Addresses - -Your firewall must allow outbound connectivity to the following Infisical relay servers on dynamically allocated ports. - - - - ``` - 54.235.197.91:49152-65535 - 18.215.196.229:49152-65535 - 3.222.120.233:49152-65535 - 34.196.115.157:49152-65535 - ``` - - - ``` - 3.125.237.40:49152-65535 - 52.28.157.98:49152-65535 - 3.125.176.90:49152-65535 - ``` - - - Please contact your Infisical account manager for dedicated relay server IP addresses. - - - - - These IP addresses are static and managed by Infisical. Any changes will be communicated with 60-day advance notice. - - -## Protocol Details - -### QUIC over UDP - -The gateway uses QUIC (Quick UDP Internet Connections) for primary communication: - -- **Port 5349**: STUN/TURN over TLS (secure relay communication) -- **Built-in features**: Connection migration, multiplexing, reduced latency -- **Encryption**: TLS 1.3 with certificate pinning - -## Understanding Firewall Behavior with UDP - -Unlike TCP connections, UDP is a stateless protocol, and depending on your organization's firewall configuration, you may need to adjust network rules accordingly. -When the gateway sends UDP packets to a relay server, the return responses need to be allowed back through the firewall. -Modern firewalls handle this through "connection tracking" (also called "stateful inspection"), but the behavior can vary depending on your firewall configuration. - - -### Connection Tracking - -Modern firewalls automatically track UDP connections and allow return responses. This is the preferred configuration as it: -- Automatically handles return responses -- Reduces firewall rule complexity -- Avoids the need for manual IP whitelisting - -In the event that your firewall does not support connection tracking, you will need to whitelist the relay IPs to explicitly define return traffic manually. - -## Common Network Scenarios - -### Corporate Firewalls - -For corporate environments with strict egress filtering: - -1. **Whitelist relay IP addresses** (listed above) -2. **Allow UDP port 5349** outbound -3. **Configure connection tracking** for UDP return traffic -4. **Allow ephemeral port range** 49152-65535 for return traffic if connection tracking is disabled - -### Cloud Environments (AWS/GCP/Azure) - -Configure security groups to allow: -- **Outbound UDP** to relay IPs on port 5349 -- **Outbound HTTPS** to app.infisical.com/eu.infisical.com on port 443 -- **Inbound UDP** on ephemeral ports (if not using stateful rules) - -## Frequently Asked Questions - - - -The gateway is designed to handle network interruptions gracefully: - -- **Automatic reconnection**: The gateway will automatically attempt to reconnect to relay servers every 5 seconds if the connection is lost -- **Connection retry logic**: Built-in retry mechanisms handle temporary network outages without manual intervention -- **Multiple relay servers**: If one relay server is unavailable, the gateway can connect to alternative relay servers -- **Persistent sessions**: Existing connections are maintained where possible during brief network interruptions -- **Graceful degradation**: The gateway logs connection issues and continues attempting to restore connectivity - -No manual intervention is typically required during network interruptions. - - - -QUIC (Quick UDP Internet Connections) provides several advantages over traditional TCP for gateway communication: - -- **Faster connection establishment**: QUIC combines transport and security handshakes, reducing connection setup time -- **Built-in encryption**: TLS 1.3 is integrated into the protocol, ensuring all traffic is encrypted by default -- **Connection migration**: QUIC connections can survive IP address changes (useful for NAT rebinding) -- **Reduced head-of-line blocking**: Multiple data streams can be multiplexed without blocking each other -- **Better performance over unreliable networks**: Advanced congestion control and packet loss recovery -- **Lower latency**: Optimized for real-time communication between gateway and cloud services - -While TCP is stateful and easier for firewalls to track, QUIC's performance benefits outweigh the additional firewall configuration requirements. - - - -No inbound ports need to be opened. The gateway only makes outbound connections: - -- **Outbound UDP** to relay servers on ports 49152-65535 -- **Outbound HTTPS** to Infisical API endpoints -- **Return responses** are handled by connection tracking or explicit IP whitelisting - -This design maintains security by avoiding the need for inbound firewall rules that could expose your network to external threats. - - - -If your firewall has strict UDP restrictions: - -1. **Work with your network team** to allow outbound UDP to the specific relay IP addresses -2. **Use explicit IP whitelisting** if connection tracking is disabled -3. **Consider network policy exceptions** for the gateway host -4. **Monitor firewall logs** to identify which specific rules are blocking traffic - -The gateway requires UDP connectivity to function - TCP-only configurations are not supported. - - - -The gateway connects to **one relay server at a time**: - -- **Single active connection**: Only one relay connection is established per gateway instance -- **Automatic failover**: If the current relay becomes unavailable, the gateway will connect to an alternative relay -- **Load distribution**: Different gateway instances may connect to different relay servers for load balancing -- **No manual selection**: The Infisical API automatically assigns the optimal relay server based on availability and proximity - -You should whitelist all relay IP addresses to ensure proper failover functionality. - - -No, relay servers cannot decrypt any traffic passing through them: - -- **End-to-end encryption**: All traffic between the gateway and Infisical Cloud is encrypted using mutual TLS with certificate pinning -- **Relay acts as a tunnel**: The relay server only forwards encrypted packets - it has no access to encryption keys -- **No data storage**: Relay servers do not store any traffic or network-identifiable information -- **Certificate isolation**: Each organization has its own private PKI system, ensuring complete tenant isolation - -The relay infrastructure is designed as a secure forwarding mechanism, similar to a VPN tunnel, where the relay provider cannot see the contents of the traffic flowing through it. - - diff --git a/docs/documentation/platform/gateways-deprecated/overview.mdx b/docs/documentation/platform/gateways-deprecated/overview.mdx deleted file mode 100644 index f81809f7b..000000000 --- a/docs/documentation/platform/gateways-deprecated/overview.mdx +++ /dev/null @@ -1,352 +0,0 @@ ---- -title: "Gateway" -sidebarTitle: "Overview" -description: "How to access private network resources from Infisical" ---- - -![Alt text](/documentation/platform/gateways-deprecated/images/gateway-highlevel-diagram.png) - -The Infisical Gateway provides secure access to private resources within your network without needing direct inbound connections to your environment. -This method keeps your resources fully protected from external access while enabling Infisical to securely interact with resources like databases. -Common use cases include generating dynamic credentials or rotating credentials for private databases. - - - Gateway is a paid feature available under the Enterprise Tier for Infisical - Cloud users. Self-hosted Infisical users can contact - [sales@infisical.com](mailto:sales@infisical.com) to purchase an enterprise - license. - - -## How It Works - -The Gateway serves as a secure intermediary that facilitates direct communication between the Infisical server and your private network. -It’s a lightweight daemon packaged within the Infisical CLI, making it easy to deploy and manage. Once set up, the Gateway establishes a connection with a relay server, ensuring that all communication between Infisical and your Gateway is fully end-to-end encrypted. -This setup guarantees that only the platform and your Gateway can decrypt the transmitted information, keeping communication with your resources secure, private and isolated. - -## Deployment - -The Infisical Gateway is seamlessly integrated into the Infisical CLI under the `gateway` command, making it simple to deploy and manage. -You can install the Gateway in all the same ways you install the Infisical CLI—whether via npm, Docker, or a binary. -For detailed installation instructions, refer to the Infisical [CLI Installation instructions](/cli/overview). - -To function, the Gateway must authenticate with Infisical. This requires a machine identity configured with the appropriate permissions to create and manage a Gateway. -Once authenticated, the Gateway establishes a secure connection with Infisical to allow your private resources to be reachable. - -### Get started - - - - 1. Navigate to **Organization Access Control** in your Infisical dashboard. - 2. Create a dedicated machine identity for your Gateway. - 3. **Best Practice:** Assign a unique identity to each Gateway for better security and management. - ![Create Gateway Identity](../../../images/platform/gateways/create-identity-for-gateway.png) - - - - You'll need to choose an authentication method to initiate communication with Infisical. View the available machine identity authentication methods [here](/documentation/platform/identities/machine-identities). - - - - Use the Infisical CLI to deploy the Gateway. You can run it directly or install it as a systemd service for production: - - - - For production deployments on Linux, install the Gateway as a systemd service: - ```bash - sudo infisical gateway install --token --domain - sudo systemctl start infisical-gateway - ``` - This will install and start the Gateway as a secure systemd service that: - - Runs with restricted privileges: - - Runs as root user (required for secure token management) - - Restricted access to home directories - - Private temporary directory - - Automatically restarts on failure - - Starts on system boot - - Manages token and domain configuration securely in `/etc/infisical/gateway.conf` - - - The install command requires: - - Linux operating system - - Root/sudo privileges - - Systemd - - - - - - The Gateway can be installed via [Helm](https://helm.sh/). Helm is a package manager for Kubernetes that allows you to define, install, and upgrade Kubernetes applications. - - For production deployments on Kubernetes, install the Gateway using the Infisical Helm chart: - - ### Install the latest Helm Chart repository - ```bash - helm repo add infisical-helm-charts 'https://dl.cloudsmith.io/public/infisical/helm-charts/helm/charts/' - ``` - - ### Update the Helm Chart repository - ```bash - helm repo update - ``` - - ### Create a Kubernetes Secret containing gateway environment variables - - The gateway supports all identity authentication methods through the use of environment variables. - The environment variables must be set in the `infisical-gateway-environment` Kubernetes secret. - - - #### Supported authentication methods - - - - The Universal Auth method is a simple and secure way to authenticate with Infisical. It requires a client ID and a client secret to authenticate with Infisical. - - - - - Your machine identity client ID. - - - Your machine identity client secret. - - - The authentication method to use. Must be `universal-auth` when using Universal Auth. - - - - - ```bash - kubectl create secret generic infisical-gateway-environment --from-literal=INFISICAL_AUTH_METHOD=universal-auth --from-literal=INFISICAL_UNIVERSAL_AUTH_CLIENT_ID= --from-literal=INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET= - ``` - - - - The Native Kubernetes method is used to authenticate with Infisical when running in a Kubernetes environment. It requires a service account token to authenticate with Infisical. - - - - - Your machine identity ID. - - - Path to the Kubernetes service account token to use. Default: `/var/run/secrets/kubernetes.io/serviceaccount/token`. - - - The authentication method to use. Must be `kubernetes` when using Native Kubernetes. - - - - - - ```bash - kubectl create secret generic infisical-gateway-environment --from-literal=INFISICAL_AUTH_METHOD=kubernetes --from-literal=INFISICAL_MACHINE_IDENTITY_ID= - ``` - - - - The Native Azure method is used to authenticate with Infisical when running in an Azure environment. - - - - - Your machine identity ID. - - - The authentication method to use. Must be `azure` when using Native Azure. - - - - - ```bash - kubectl create secret generic infisical-gateway-environment --from-literal=INFISICAL_AUTH_METHOD=azure --from-literal=INFISICAL_MACHINE_IDENTITY_ID= - ``` - - - The Native GCP ID Token method is used to authenticate with Infisical when running in a GCP environment. - - - - - Your machine identity ID. - - - The authentication method to use. Must be `gcp-id-token` when using Native GCP ID Token. - - - - - ```bash - kubectl create secret generic infisical-gateway-environment --from-literal=INFISICAL_AUTH_METHOD=gcp-id-token --from-literal=INFISICAL_MACHINE_IDENTITY_ID= - ``` - - - - The GCP IAM method is used to authenticate with Infisical with a GCP service account key. - - - - - Your machine identity ID. - - - Path to your GCP service account key file _(Must be in JSON format!)_ - - - The authentication method to use. Must be `gcp-iam` when using GCP IAM. - - - - - ```bash - kubectl create secret generic infisical-gateway-environment --from-literal=INFISICAL_AUTH_METHOD=gcp-iam --from-literal=INFISICAL_MACHINE_IDENTITY_ID= --from-literal=INFISICAL_GCP_SERVICE_ACCOUNT_KEY_FILE_PATH= - ``` - - - - - The AWS IAM method is used to authenticate with Infisical with an AWS IAM role while running in an AWS environment like EC2, Lambda, etc. - - - - - Your machine identity ID. - - - The authentication method to use. Must be `aws-iam` when using Native AWS IAM. - - - - - ```bash - kubectl create secret generic infisical-gateway-environment --from-literal=INFISICAL_AUTH_METHOD=aws-iam --from-literal=INFISICAL_MACHINE_IDENTITY_ID= - ``` - - - - The OIDC Auth method is used to authenticate with Infisical via identity tokens with OIDC. - - - - - Your machine identity ID. - - - The OIDC JWT from the identity provider. - - - The authentication method to use. Must be `oidc-auth` when using OIDC Auth. - - - - - ```bash - kubectl create secret generic infisical-gateway-environment --from-literal=INFISICAL_AUTH_METHOD=oidc-auth --from-literal=INFISICAL_MACHINE_IDENTITY_ID= --from-literal=INFISICAL_JWT= - ``` - - - - The JWT Auth method is used to authenticate with Infisical via a JWT token. - - - - - The JWT token to use for authentication. - - - Your machine identity ID. - - - The authentication method to use. Must be `jwt-auth` when using JWT Auth. - - - - - ```bash - kubectl create secret generic infisical-gateway-environment --from-literal=INFISICAL_AUTH_METHOD=jwt-auth --from-literal=INFISICAL_JWT= --from-literal=INFISICAL_MACHINE_IDENTITY_ID= - ``` - - - You can use the `INFISICAL_TOKEN` environment variable to authenticate with Infisical with a raw machine identity access token. - - - - - The machine identity access token to use for authentication. - - - - - ```bash - kubectl create secret generic infisical-gateway-environment --from-literal=INFISICAL_TOKEN= - ``` - - - - - #### Other environment variables - - - - The API URL to use for the gateway. By default, `INFISICAL_API_URL` is set to `https://app.infisical.com`. - - - - - ### Install the Infisical Gateway Helm Chart - ```bash - helm install infisical-gateway infisical-helm-charts/infisical-gateway - ``` - - ### Check the gateway logs - After installing the gateway, you can check the logs to ensure it's running as expected. - - ```bash - kubectl logs deployment/infisical-gateway - ``` - - You should see the following output which indicates the gateway is running as expected. - ```bash - $ kubectl logs deployment/infisical-gateway - INF Provided relay port 5349. Using TLS - INF Connected with relay - INF 10.0.101.112:56735 - INF Starting relay connection health check - INF Gateway started successfully - INF New connection from: 10.0.1.8:34051 - INF Gateway is reachable by Infisical - ``` - - - - - For development or testing, you can run the Gateway directly. Log in with your machine identity and start the Gateway in one command: - ```bash - infisical gateway --token $(infisical login --method=universal-auth --client-id=<> --client-secret=<> --plain) - ``` - - Alternatively, if you already have the token, use it directly with the `--token` flag: - ```bash - infisical gateway --token - ``` - - Or set it as an environment variable: - ```bash - export INFISICAL_TOKEN= - infisical gateway - ``` - - - - For detailed information about the gateway command and its options, see the [gateway command documentation](/cli/commands/gateway). - - - Ensure the deployed Gateway has network access to the private resources you intend to connect with Infisical. - - - - - - To confirm your Gateway is working, check the deployment status by looking for the message **"Gateway started successfully"** in the Gateway logs. This indicates the Gateway is running properly. Next, verify its registration by opening your Infisical dashboard, navigating to **Organization Access Control**, and selecting the **Gateways** tab. Your newly deployed Gateway should appear in the list. - ![Gateway List](../../../images/platform/gateways/gateway-list.png) - - From 6d95985eece1988d5793eff24604b6267ce1fe9a Mon Sep 17 00:00:00 2001 From: Scott Wilson Date: Thu, 23 Oct 2025 09:30:30 -0700 Subject: [PATCH 087/146] feat: add storybook and new badge component with stories --- frontend/.gitignore | 3 + .../.storybook/decorators/RouterDecorator.tsx | 17 + frontend/.storybook/decorators/index.ts | 1 + frontend/.storybook/main.ts | 14 + frontend/.storybook/preview.tsx | 45 + frontend/eslint.config.js | 6 +- frontend/package-lock.json | 2089 +++++++++++++++-- frontend/package.json | 12 +- frontend/public/fonts/AllianceNo2-Regular.otf | Bin 0 -> 134048 bytes .../public/images/logotransparent_trimmed.png | Bin 0 -> 35972 bytes .../lotties/infisical_loading_white.json | 1 + .../v3/generic/Badge/Badge.stories.tsx | 307 +++ .../src/components/v3/generic/Badge/Badge.tsx | 82 + .../src/components/v3/generic/Badge/index.ts | 1 + frontend/src/components/v3/generic/index.ts | 1 + frontend/src/components/v3/index.ts | 0 frontend/src/components/v3/utils/index.ts | 6 + frontend/src/index.css | 18 +- frontend/tsconfig.app.json | 2 + 19 files changed, 2437 insertions(+), 168 deletions(-) create mode 100644 frontend/.storybook/decorators/RouterDecorator.tsx create mode 100644 frontend/.storybook/decorators/index.ts create mode 100644 frontend/.storybook/main.ts create mode 100644 frontend/.storybook/preview.tsx create mode 100644 frontend/public/fonts/AllianceNo2-Regular.otf create mode 100644 frontend/public/images/logotransparent_trimmed.png create mode 100644 frontend/public/lotties/infisical_loading_white.json create mode 100644 frontend/src/components/v3/generic/Badge/Badge.stories.tsx create mode 100644 frontend/src/components/v3/generic/Badge/Badge.tsx create mode 100644 frontend/src/components/v3/generic/Badge/index.ts create mode 100644 frontend/src/components/v3/generic/index.ts create mode 100644 frontend/src/components/v3/index.ts create mode 100644 frontend/src/components/v3/utils/index.ts diff --git a/frontend/.gitignore b/frontend/.gitignore index a547bf36d..f52343a92 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -22,3 +22,6 @@ dist-ssr *.njsproj *.sln *.sw? + +*storybook.log +storybook-static diff --git a/frontend/.storybook/decorators/RouterDecorator.tsx b/frontend/.storybook/decorators/RouterDecorator.tsx new file mode 100644 index 000000000..06f8d7575 --- /dev/null +++ b/frontend/.storybook/decorators/RouterDecorator.tsx @@ -0,0 +1,17 @@ +import type { Decorator } from "@storybook/react-vite"; +import { createRootRoute, createRouter, RouterProvider } from "@tanstack/react-router"; + +export const RouterDecorator: Decorator = (Story) => { + const rootRoute = createRootRoute({ + component: Story + }); + + const routeTree = rootRoute; + + const router = createRouter({ + routeTree + }); + + // @ts-expect-error just to make Links happy :) + return ; +}; diff --git a/frontend/.storybook/decorators/index.ts b/frontend/.storybook/decorators/index.ts new file mode 100644 index 000000000..b613f5c6a --- /dev/null +++ b/frontend/.storybook/decorators/index.ts @@ -0,0 +1 @@ +export * from "./RouterDecorator"; diff --git a/frontend/.storybook/main.ts b/frontend/.storybook/main.ts new file mode 100644 index 000000000..0a7b7adb5 --- /dev/null +++ b/frontend/.storybook/main.ts @@ -0,0 +1,14 @@ +import type { StorybookConfig } from "@storybook/react-vite"; + +const config: StorybookConfig = { + stories: [ + "../src/components/v3/**/*.mdx", + "../src/components/v3/**/*.stories.@(js|jsx|mjs|ts|tsx)" + ], + addons: ["@storybook/addon-docs", "@storybook/addon-a11y"], + framework: { + name: "@storybook/react-vite", + options: {} + } +}; +export default config; diff --git a/frontend/.storybook/preview.tsx b/frontend/.storybook/preview.tsx new file mode 100644 index 000000000..67157339d --- /dev/null +++ b/frontend/.storybook/preview.tsx @@ -0,0 +1,45 @@ +import type { Preview } from "@storybook/react-vite"; + +import { RouterDecorator } from "./decorators"; + +import "../src/index.css"; + +const preview: Preview = { + decorators: [ + (Story) => { + const root = document.getElementsByTagName("html")[0]; + + root.setAttribute("class", "overflow-visible"); + + return ; + }, + RouterDecorator + ], + parameters: { + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i + } + }, + docs: { + backgroundColor: "var(--background)" + }, + a11y: { + test: "todo" + }, + backgrounds: { + default: "dark", + options: { + dark: { name: "Dark", value: "var(--background)" } + } + } + }, + initialGlobals: { + backgrounds: { + value: "dark" + } + } +}; + +export default preview; diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js index 00c024056..843a9602e 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.js @@ -1,3 +1,6 @@ +// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format +import storybook from "eslint-plugin-storybook"; + import js from "@eslint/js"; import globals from "globals"; import reactHooks from "eslint-plugin-react-hooks"; @@ -133,5 +136,6 @@ export default tseslint.config( rules: Object.fromEntries( Object.keys(stylisticPlugin.configs["all-flat"].rules ?? {}).map((key) => [key, "off"]) ) - } + }, + storybook.configs["flat/recommended"] ); diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a9f4b070c..6e20b6d35 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -40,7 +40,9 @@ "@radix-ui/react-popper": "^1.2.1", "@radix-ui/react-progress": "^1.1.1", "@radix-ui/react-radio-group": "^1.2.2", + "@radix-ui/react-scroll-area": "^1.2.10", "@radix-ui/react-select": "^2.1.3", + "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-switch": "^1.1.2", "@radix-ui/react-tabs": "^1.1.2", "@radix-ui/react-toast": "^1.2.3", @@ -57,6 +59,7 @@ "argon2-browser": "^1.18.0", "axios": "^1.12.0", "classnames": "^2.5.1", + "clsx": "^2.1.1", "cva": "npm:class-variance-authority@^0.7.1", "date-fns": "^4.1.0", "dompurify": "^3.2.4", @@ -69,6 +72,7 @@ "jsrp": "^0.2.4", "jwt-decode": "^4.0.0", "lexical": "^0.29.0", + "lucide-react": "^0.544.0", "ms": "^2.1.3", "nprogress": "^0.2.0", "picomatch": "^4.0.2", @@ -98,6 +102,9 @@ "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.15.0", "@kesills/eslint-config-airbnb-typescript": "^20.0.0", + "@storybook/addon-a11y": "^9.1.9", + "@storybook/addon-docs": "^9.1.9", + "@storybook/react-vite": "^9.1.9", "@stylistic/eslint-plugin": "^2.12.1", "@tailwindcss/postcss": "^4.1.14", "@tailwindcss/typography": "^0.5.15", @@ -123,6 +130,7 @@ "eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-react-refresh": "^0.4.14", "eslint-plugin-simple-import-sort": "^12.1.1", + "eslint-plugin-storybook": "^9.1.9", "globals": "^15.12.0", "postcss": "^8.4.49", "prettier": "3.4.2", @@ -137,6 +145,14 @@ "vite-tsconfig-paths": "^5.1.4" } }, + "node_modules/@adobe/css-tools": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", + "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -150,38 +166,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz", - "integrity": "sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", "dev": true, "license": "MIT", "engines": { @@ -189,22 +191,22 @@ } }, "node_modules/@babel/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", - "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "dev": true, "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -243,15 +245,15 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", - "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.3", - "@babel/types": "^7.26.3", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { @@ -259,14 +261,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", - "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -275,16 +277,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -295,29 +287,38 @@ "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -337,27 +338,27 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -365,26 +366,26 @@ } }, "node_modules/@babel/helpers": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz", - "integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.10" + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz", - "integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.26.10" + "@babel/types": "^7.28.4" }, "bin": { "parser": "bin/babel-parser.js" @@ -438,54 +439,45 @@ } }, "node_modules/@babel/template": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", - "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.26.9", - "@babel/types": "^7.26.9" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.26.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", - "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.3", - "@babel/parser": "^7.26.3", - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.3", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/types": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz", - "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1454,6 +1446,53 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", @@ -1467,18 +1506,82 @@ "node": ">=18.0.0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.6.1.tgz", + "integrity": "sha512-J4BaTocTOYFkMHIra1JDWrMWpNmBl4EkplIwHEsV8aeUOtdWjwSnln9U7twjMFTAEB7mptNtSKyVi1Y2W9sDJw==", + "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" + "glob": "^10.0.0", + "magic-string": "^0.30.0", + "react-docgen-typescript": "^2.2.2" + }, + "peerDependencies": { + "typescript": ">= 4.3.x", + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=6.0.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, "node_modules/@jridgewell/remapping": { @@ -1501,15 +1604,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -1517,9 +1611,9 @@ "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1822,6 +1916,24 @@ "integrity": "sha512-01d+UjJ8NG7ZStYQxtb8FPzknzGmauG7gEkcH+wHfSdiSQJY9PoBNVSTB9V6F5hAnmFqOxaocTtd7TIEEnzMnA==", "license": "MIT" }, + "node_modules/@mdx-js/react": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", + "integrity": "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdx": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2170,6 +2282,17 @@ "tsyringe": "^4.8.0" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@pkgr/core": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", @@ -2254,6 +2377,24 @@ } } }, + "node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", + "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-arrow": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.1.tgz", @@ -2363,6 +2504,24 @@ } } }, + "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", + "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", @@ -2429,6 +2588,24 @@ } } }, + "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", + "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-direction": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz", @@ -2652,6 +2829,24 @@ } } }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", + "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popover": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.3.tgz", @@ -2689,6 +2884,24 @@ } } }, + "node_modules/@radix-ui/react-popover/node_modules/@radix-ui/react-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", + "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.1.tgz", @@ -2792,6 +3005,24 @@ } } }, + "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", + "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-progress": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.1.tgz", @@ -2879,6 +3110,171 @@ } } }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", + "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-scroll-area/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-select": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.3.tgz", @@ -2922,7 +3318,7 @@ } } }, - "node_modules/@radix-ui/react-slot": { + "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-slot": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", @@ -2940,6 +3336,39 @@ } } }, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-switch": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.1.2.tgz", @@ -3067,6 +3496,24 @@ } } }, + "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.1.tgz", + "integrity": "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz", @@ -3605,6 +4052,297 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@storybook/addon-a11y": { + "version": "9.1.13", + "resolved": "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-9.1.13.tgz", + "integrity": "sha512-4enIl1h2XSZnFKUQJJoZbp1X40lzdj7f5JE15ZhU1al4z6hHWp7i2zD7ySyDpEbMypBCz1xnLvyiyw79m1fp7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "axe-core": "^4.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^9.1.13" + } + }, + "node_modules/@storybook/addon-docs": { + "version": "9.1.13", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-9.1.13.tgz", + "integrity": "sha512-V1nCo7bfC3kQ5VNVq0VDcHsIhQf507m+BxMA5SIYiwdJHljH2BXpW2fL3FFn9gv9Wp57AEEzhm+wh4zANaJgkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mdx-js/react": "^3.0.0", + "@storybook/csf-plugin": "9.1.13", + "@storybook/icons": "^1.4.0", + "@storybook/react-dom-shim": "9.1.13", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^9.1.13" + } + }, + "node_modules/@storybook/builder-vite": { + "version": "9.1.13", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-9.1.13.tgz", + "integrity": "sha512-pmtIjU02ASJOZKdL8DoxWXJgZnpTDgD5WmMnjKJh9FaWmc2YiCW2Y6VRxPox96OM655jYHQe5+UIbk3Cwtwb4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/csf-plugin": "9.1.13", + "ts-dedent": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^9.1.13", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@storybook/csf-plugin": { + "version": "9.1.13", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-9.1.13.tgz", + "integrity": "sha512-EMpzYuyt9FDcxxfBChWzfId50y8QMpdenviEQ8m+pa6c+ANx3pC5J6t7y0khD8TQu815sTy+nc6cc8PC45dPUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "unplugin": "^1.3.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "storybook": "^9.1.13" + } + }, + "node_modules/@storybook/global": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz", + "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@storybook/icons": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-1.6.0.tgz", + "integrity": "sha512-hcFZIjW8yQz8O8//2WTIXylm5Xsgc+lW9ISLgUk1xGmptIJQRdlhVIXCpSyLrQaaRiyhQRaVg7l3BD9S216BHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta" + } + }, + "node_modules/@storybook/react": { + "version": "9.1.13", + "resolved": "https://registry.npmjs.org/@storybook/react/-/react-9.1.13.tgz", + "integrity": "sha512-B0UpYikKf29t8QGcdmumWojSQQ0phSDy/Ne2HYdrpNIxnUvHHUVOlGpq4lFcIDt52Ip5YG5GuAwJg3+eR4LCRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@storybook/global": "^5.0.0", + "@storybook/react-dom-shim": "9.1.13" + }, + "engines": { + "node": ">=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^9.1.13", + "typescript": ">= 4.9.x" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@storybook/react-dom-shim": { + "version": "9.1.13", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-9.1.13.tgz", + "integrity": "sha512-/tMr9TmV3+98GEQO0S03k4gtKHGCpv9+k9Dmnv+TJK3TBz7QsaFEzMwe3gCgoTaebLACyVveDiZkWnCYAWB6NA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^9.1.13" + } + }, + "node_modules/@storybook/react-vite": { + "version": "9.1.13", + "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-9.1.13.tgz", + "integrity": "sha512-mV1bZ1bpkNQygnuDo1xMGAS5ZXuoXFF0WGmr/BzNDGmRhZ1K1HQh42kC0w3PklckFBUwCFxmP58ZwTFzf+/dJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@joshwooding/vite-plugin-react-docgen-typescript": "0.6.1", + "@rollup/pluginutils": "^5.0.2", + "@storybook/builder-vite": "9.1.13", + "@storybook/react": "9.1.13", + "find-up": "^7.0.0", + "magic-string": "^0.30.0", + "react-docgen": "^8.0.0", + "resolve": "^1.22.8", + "tsconfig-paths": "^4.2.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta", + "storybook": "^9.1.13", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@storybook/react-vite/node_modules/find-up": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", + "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/react-vite/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/react-vite/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/react-vite/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/react-vite/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@storybook/react-vite/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@storybook/react-vite/node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@storybook/react-vite/node_modules/yocto-queue": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@stylistic/eslint-plugin": { "version": "2.13.0", "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.13.0.tgz", @@ -4441,6 +5179,82 @@ "zod": "^3.23.8" } }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@testing-library/user-event": { + "version": "14.6.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", + "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, "node_modules/@types/argon2-browser": { "version": "1.18.4", "resolved": "https://registry.npmjs.org/@types/argon2-browser/-/argon2-browser-1.18.4.tgz", @@ -4448,6 +5262,14 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -4484,13 +5306,25 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.20.7" + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" } }, "node_modules/@types/d3-color": { @@ -4556,6 +5390,21 @@ "@types/ms": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/doctrine": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz", + "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", @@ -4607,6 +5456,13 @@ "@types/unist": "*" } }, + "node_modules/@types/mdx": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", + "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/ms": { "version": "0.7.34", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", @@ -4710,6 +5566,13 @@ "@types/react": "*" } }, + "node_modules/@types/resolve": { + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz", + "integrity": "sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", @@ -5032,6 +5895,107 @@ "vite": "^4 || ^5 || ^6" } }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@xyflow/react": { "version": "12.4.4", "resolved": "https://registry.npmjs.org/@xyflow/react/-/react-12.4.4.tgz", @@ -5424,6 +6388,31 @@ "util": "^0.12.5" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/ast-types-flow": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", @@ -5459,7 +6448,6 @@ "integrity": "sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==", "dev": true, "license": "MPL-2.0", - "peer": true, "engines": { "node": ">=4" } @@ -5561,12 +6549,36 @@ ], "license": "MIT" }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.19.tgz", + "integrity": "sha512-zoKGUdu6vb2jd3YOq0nnhEDQVbPcHhco3UImJrv5dSkvxTc2pl2WjOPsjZXDwPDSl5eghIMuY3R6J9NDKF3KcQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, "node_modules/before-after-hook": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz", "integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==", "license": "Apache-2.0" }, + "node_modules/better-opn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz", + "integrity": "sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "open": "^8.0.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -5777,9 +6789,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", - "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "version": "4.26.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", + "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", "dev": true, "funding": [ { @@ -5797,10 +6809,11 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001669", - "electron-to-chromium": "^1.5.41", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.1" + "baseline-browser-mapping": "^2.8.9", + "caniuse-lite": "^1.0.30001746", + "electron-to-chromium": "^1.5.227", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" @@ -5914,9 +6927,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001688", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001688.tgz", - "integrity": "sha512-Nmqpru91cuABu/DTCXbM2NSRHzM2uVHfPnhJ/1zEAJx/ILBRVmz3pzH4N7DZqbdG0gWClsCC05Oj0mJ/1AWMbA==", + "version": "1.0.30001751", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", + "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", "dev": true, "funding": [ { @@ -5970,6 +6983,24 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -6023,6 +7054,17 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 16" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -6399,6 +7441,14 @@ "utrie": "^1.0.2" } }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -6646,6 +7696,17 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -6670,6 +7731,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -6782,6 +7854,14 @@ "node": ">=6.0.0" } }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/dom-helpers": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", @@ -6827,10 +7907,17 @@ "node": ">= 0.4" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, "node_modules/electron-to-chromium": { - "version": "1.5.73", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.73.tgz", - "integrity": "sha512-8wGNxG9tAG5KhGd3eeA0o6ixhiNdgr0DcHWm85XPCphwZgD1lIEoi6t3VERayWao7SF7AAZTw6oARGJeVjH8Kg==", + "version": "1.5.237", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.237.tgz", + "integrity": "sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==", "dev": true, "license": "ISC" }, @@ -6862,8 +7949,7 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/enhanced-resolve": { "version": "5.18.3", @@ -7100,6 +8186,20 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/esbuild-register": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", + "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -7570,6 +8670,23 @@ "eslint": ">=5.0.0" } }, + "node_modules/eslint-plugin-storybook": { + "version": "9.1.13", + "resolved": "https://registry.npmjs.org/eslint-plugin-storybook/-/eslint-plugin-storybook-9.1.13.tgz", + "integrity": "sha512-kPuhbtGDiJLB5OLZuwFZAxgzWakNDw64sJtXUPN8g0+VAeXfHyZEmsE28qIIETHxtal71lPKVm8QNnERaJHPJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.8.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "eslint": ">=8", + "storybook": "^9.1.13" + } + }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", @@ -7694,6 +8811,21 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -7995,6 +9127,23 @@ "is-callable": "^1.1.3" } }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", @@ -8768,6 +9917,17 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -9034,6 +10194,23 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -9339,6 +10516,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -9392,6 +10583,22 @@ "node": ">= 0.4" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jiti": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", @@ -9910,6 +11117,44 @@ "loose-envify": "cli.js" } }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.544.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.544.0.tgz", + "integrity": "sha512-t5tS44bqd825zAW45UQxpG2CvcC4urOwn2TrwSH8u+MjeE+1NnWl6QqeQ/6NdjMqdOygyiT9p3Ev0p1NJykxjw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/magic-string": { "version": "0.30.19", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", @@ -10591,6 +11836,17 @@ "node": ">= 0.6" } }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -10716,9 +11972,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "version": "2.0.26", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.26.tgz", + "integrity": "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==", "dev": true, "license": "MIT" }, @@ -10929,6 +12185,25 @@ "wrappy": "1" } }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -10995,6 +12270,13 @@ "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -11140,6 +12422,30 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -11149,6 +12455,17 @@ "node": ">=8" } }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 14.16" + } + }, "node_modules/pbkdf2": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", @@ -11406,6 +12723,44 @@ } } }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/prismjs": { "version": "1.30.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", @@ -11686,6 +13041,38 @@ "react": ">=16.8.0" } }, + "node_modules/react-docgen": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-8.0.2.tgz", + "integrity": "sha512-+NRMYs2DyTP4/tqWz371Oo50JqmWltR1h2gcdgUMAWZJIAvrd0/SqlCfx7tpzpl/s36rzw6qH2MjoNrxtRNYhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.2", + "@types/babel__core": "^7.20.5", + "@types/babel__traverse": "^7.20.7", + "@types/doctrine": "^0.0.9", + "@types/resolve": "^1.20.2", + "doctrine": "^3.0.0", + "resolve": "^1.22.1", + "strip-indent": "^4.0.0" + }, + "engines": { + "node": "^20.9.0 || >=22" + } + }, + "node_modules/react-docgen-typescript": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.4.0.tgz", + "integrity": "sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">= 4.3.x" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -11985,12 +13372,70 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/recast": { + "version": "0.23.11", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz", + "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/recast/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/redaxios": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/redaxios/-/redaxios-0.5.1.tgz", "integrity": "sha512-FSD2AmfdbkYwl7KDExYQlVvIrFz6Yd83pGfaGjBzM9F6rpq8g652Q4Yq5QD4c+nf4g2AgeElv1y+8ajUPiOYMg==", "license": "Apache-2.0" }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redent/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", @@ -12500,6 +13945,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -12545,6 +14003,43 @@ "node": ">=0.1.14" } }, + "node_modules/storybook": { + "version": "9.1.13", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-9.1.13.tgz", + "integrity": "sha512-G3KZ36EVzXyHds72B/qtWiJnhUpM0xOUeYlDcO9DSHL1bDTv15cW4+upBl+mcBZrDvU838cn7Bv4GpF+O5MCfw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@storybook/global": "^5.0.0", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/user-event": "^14.6.1", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/spy": "3.2.4", + "better-opn": "^3.0.2", + "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0", + "esbuild-register": "^3.5.0", + "recast": "^0.23.5", + "semver": "^7.6.2", + "ws": "^8.18.0" + }, + "bin": { + "storybook": "bin/index.cjs" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "peerDependencies": { + "prettier": "^2 || ^3" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + } + } + }, "node_modules/stream-browserify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", @@ -12579,6 +14074,76 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -12719,6 +14284,20 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -12729,6 +14308,19 @@ "node": ">=4" } }, + "node_modules/strip-indent": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.1.tgz", + "integrity": "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -12904,6 +14496,28 @@ "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", "license": "MIT" }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/to-buffer": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", @@ -12968,6 +14582,16 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, "node_modules/tsconfck": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.4.tgz", @@ -13660,6 +15284,19 @@ "dev": true, "license": "MIT" }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/unified": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", @@ -13762,9 +15399,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, "funding": [ { @@ -13783,7 +15420,7 @@ "license": "MIT", "dependencies": { "escalade": "^3.2.0", - "picocolors": "^1.1.0" + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -14266,6 +15903,107 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -14273,6 +16011,29 @@ "dev": true, "license": "ISC" }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index d89025650..9c375190e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,7 +9,9 @@ "preview": "vite preview", "lint": "eslint ./src", "lint:fix": "eslint --fix ./src", - "type:check": "tsc --noEmit --project ./tsconfig.app.json" + "type:check": "tsc --noEmit --project ./tsconfig.app.json", + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build" }, "overrides": { "sha.js": "2.4.12" @@ -47,7 +49,9 @@ "@radix-ui/react-popper": "^1.2.1", "@radix-ui/react-progress": "^1.1.1", "@radix-ui/react-radio-group": "^1.2.2", + "@radix-ui/react-scroll-area": "^1.2.10", "@radix-ui/react-select": "^2.1.3", + "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-switch": "^1.1.2", "@radix-ui/react-tabs": "^1.1.2", "@radix-ui/react-toast": "^1.2.3", @@ -64,6 +68,7 @@ "argon2-browser": "^1.18.0", "axios": "^1.12.0", "classnames": "^2.5.1", + "clsx": "^2.1.1", "cva": "npm:class-variance-authority@^0.7.1", "date-fns": "^4.1.0", "dompurify": "^3.2.4", @@ -76,6 +81,7 @@ "jsrp": "^0.2.4", "jwt-decode": "^4.0.0", "lexical": "^0.29.0", + "lucide-react": "^0.544.0", "ms": "^2.1.3", "nprogress": "^0.2.0", "picomatch": "^4.0.2", @@ -105,6 +111,9 @@ "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.15.0", "@kesills/eslint-config-airbnb-typescript": "^20.0.0", + "@storybook/addon-a11y": "^9.1.9", + "@storybook/addon-docs": "^9.1.9", + "@storybook/react-vite": "^9.1.9", "@stylistic/eslint-plugin": "^2.12.1", "@tailwindcss/postcss": "^4.1.14", "@tailwindcss/typography": "^0.5.15", @@ -130,6 +139,7 @@ "eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-react-refresh": "^0.4.14", "eslint-plugin-simple-import-sort": "^12.1.1", + "eslint-plugin-storybook": "^9.1.9", "globals": "^15.12.0", "postcss": "^8.4.49", "prettier": "3.4.2", diff --git a/frontend/public/fonts/AllianceNo2-Regular.otf b/frontend/public/fonts/AllianceNo2-Regular.otf new file mode 100644 index 0000000000000000000000000000000000000000..a51796093db2371d306f801f12bd95b89ffd83ab GIT binary patch literal 134048 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

+ +
+ ) +}; diff --git a/frontend/src/components/v3/generic/Badge/Badge.tsx b/frontend/src/components/v3/generic/Badge/Badge.tsx new file mode 100644 index 000000000..ada354e7d --- /dev/null +++ b/frontend/src/components/v3/generic/Badge/Badge.tsx @@ -0,0 +1,82 @@ +import { forwardRef } from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "cva"; + +import { cn } from "@app/components/v3/utils"; + +const badgeVariants = cva( + [ + "select-none items-center rounded-sm px-1.5 py-0.5 text-xs", + "gap-x-1 [a&,button&]:cursor-pointer inline-flex", + "[&>svg]:pointer-events-none [&>svg]:shrink-0 [&>svg]:stroke-[2.25] [&>svg]:size-3", + "transition duration-200 ease-in-out" + ], + { + variants: { + isTruncatable: { + true: "[&>span,&>p]:truncate min-w-0", + false: "w-fit shrink-0 whitespace-nowrap overflow-hidden" + }, + variant: { + neutral: [ + "border-neutral/75 bg-neutral/30 text-neutral", + "[a&,button&]:hover:bg-neutral/40 [a&,button&]:hover:border-neutral" + ], + success: [ + "border-success/75 bg-success/30 text-success", + "[a&,button&]:hover:bg-success/40 [a&,button&]:hover:border-success" + ], + info: [ + "border-info/75 bg-info/30 text-info", + "[a&,button&]:hover:bg-info/40 [a&,button&]:hover:border-info" + ], + warning: [ + "border-warning/75 bg-warning/30 text-warning", + "[a&,button&]:hover:bg-warning/40 [a&,button&]:hover:border-warning" + ], + danger: [ + "border-danger/75 bg-danger/30 text-danger", + "[a&,button&]:hover:bg-danger/40 [a&,button&]:hover:border-danger" + ], + project: [ + "border-project/75 bg-project/30 text-project", + "[a&,button&]:hover:bg-project/40 [a&,button&]:hover:border-project" + ], + org: [ + "border-org/75 bg-org/30 text-org", + "[a&,button&]:hover:bg-org/40 [a&,button&]:hover:border-org" + ], + "sub-org": [ + "border-sub-org/75 bg-sub-org/30 text-sub-org", + "[a&,button&]:hover:bg-sub-org/40 [a&,button&]:hover:border-sub-org" + ] + } + }, + defaultVariants: { + variant: "success" + } + } +); + +type TBadgeProps = VariantProps & + React.ComponentProps<"span"> & { + asChild?: boolean; + }; + +const Badge = forwardRef( + ({ className, variant, asChild = false, isTruncatable = false, ...props }, ref): JSX.Element => { + const Comp = asChild ? Slot : "span"; + return ( + + ); + } +); + +Badge.displayName = "Badge"; + +export { Badge, badgeVariants, type TBadgeProps }; diff --git a/frontend/src/components/v3/generic/Badge/index.ts b/frontend/src/components/v3/generic/Badge/index.ts new file mode 100644 index 000000000..ae21190ba --- /dev/null +++ b/frontend/src/components/v3/generic/Badge/index.ts @@ -0,0 +1 @@ +export * from "./Badge"; diff --git a/frontend/src/components/v3/generic/index.ts b/frontend/src/components/v3/generic/index.ts new file mode 100644 index 000000000..ae21190ba --- /dev/null +++ b/frontend/src/components/v3/generic/index.ts @@ -0,0 +1 @@ +export * from "./Badge"; diff --git a/frontend/src/components/v3/index.ts b/frontend/src/components/v3/index.ts new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/components/v3/utils/index.ts b/frontend/src/components/v3/utils/index.ts new file mode 100644 index 000000000..365058ceb --- /dev/null +++ b/frontend/src/components/v3/utils/index.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/frontend/src/index.css b/frontend/src/index.css index 7c9b7db9b..2a1da3fa2 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -37,12 +37,26 @@ } @theme { - /*legacy color schema */ /* Fonts */ --font-inter: "Inter", sans-serif; + --max-width-8xl: 88rem; /* 1408px */ + + /* Colors v2 */ + --color-background: #19191c; + --color-foreground: white; + --color-success: #2ecc71; + --color-info: #34c2db; + --color-warning: #f1c40f; + --color-danger: #e74c3c; + --color-org: #30B3FF; + --color-sub-org: #96ff59; + --color-project: #e0ed34; + --color-neutral: #adaeb0; + + /*legacy color schema */ --color-org-v1: #30B3FF; --color-namespace-v1: #96ff59; - --max-width-8xl: 88rem; /* 1408px */ + /* Primary */ --color-primary-50: #fffff5; --color-primary-100: #fcfce8; diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json index 49ac1742b..690a1155d 100644 --- a/frontend/tsconfig.app.json +++ b/frontend/tsconfig.app.json @@ -31,5 +31,7 @@ "include": [ "./src/**/*.ts", "./src/**/*.tsx", + "./.storybook/**/*.ts", + "./.storybook/**/*.tsx", ], } From 6b7819cd94eddb6d3787c892bc5efa722bd0d23c Mon Sep 17 00:00:00 2001 From: x032205 Date: Thu, 23 Oct 2025 12:33:47 -0400 Subject: [PATCH 088/146] delete lingering gateway images --- .../platform/gateways/assign-project.png | Bin 346495 -> 0 bytes .../gateways/create-identity-for-gateway.png | Bin 383861 -> 0 bytes .../platform/gateways/dynamic-secret.png | Bin 393478 -> 0 bytes docs/images/platform/gateways/edit-gateway.png | Bin 373833 -> 0 bytes docs/images/platform/gateways/gateway-list.png | Bin 443518 -> 0 bytes 5 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/images/platform/gateways/assign-project.png delete mode 100644 docs/images/platform/gateways/create-identity-for-gateway.png delete mode 100644 docs/images/platform/gateways/dynamic-secret.png delete mode 100644 docs/images/platform/gateways/edit-gateway.png delete mode 100644 docs/images/platform/gateways/gateway-list.png diff --git a/docs/images/platform/gateways/assign-project.png b/docs/images/platform/gateways/assign-project.png deleted file mode 100644 index a1ff619096f4ff89e0d14d240db33ed1f4e69e07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 346495 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

eSxcdgZgmdaz7SVj0b``jRy-L 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%0A&F7&A?QSseNeBY7jHik{A+FvhJjqQu- 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

=@bn5~WE3e))^{ZE(J5$b;I&=dIR_mroNl(|& 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 &5g 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 z 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 X43hUiE@lt(f~2qEz8c^7Li+yzg5r~7 literal 0 HcmV?d00001 diff --git a/frontend/public/images/logotransparent_trimmed.png b/frontend/public/images/logotransparent_trimmed.png new file mode 100644 index 0000000000000000000000000000000000000000..32911fb83fe16ab9de659322d4ca9a40224dbb32 GIT binary patch literal 35972 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 + +export default meta; +type Story = StoryObj; + +export const Neutral: Story = { + name: "Variant: Neutral", + args: { + variant: "neutral", + children: ( + <> + + Disabled + + ) + }, + parameters: { + docs: { + description: { + story: "Use this variant when indicating neutral or disabled states." + } + } + } +}; + +export const Success: Story = { + name: "Variant: Success", + args: { + variant: "success", + children: ( + <> + + Success + + ) + }, + parameters: { + docs: { + description: { + story: "Use this variant when indicating successful or healthy states." + } + } + } +}; + +export const Info: Story = { + name: "Variant: Info", + args: { + variant: "info", + children: ( + <> + + Info + + ) + }, + parameters: { + docs: { + description: { + story: + "Use this variant when indicating informational states or linking to external references." + } + } + } +}; + +export const Warning: Story = { + name: "Variant: Warning", + args: { + variant: "warning", + children: ( + <> + + Warning + + ) + }, + parameters: { + docs: { + description: { + story: "Use this variant when indicating activity or attention warranting states." + } + } + } +}; + +export const Danger: Story = { + name: "Variant: Danger", + args: { + variant: "danger", + children: ( + <> + + Danger + + ) + }, + parameters: { + docs: { + description: { + story: "Use this variant when indicating destructive or error states." + } + } + } +}; + +export const Organization: Story = { + name: "Variant: Organization", + args: { + variant: "org", + children: ( + <> + + Organization + + ) + }, + parameters: { + docs: { + description: { + story: "Use this variant when indicating organization scope or links." + } + } + } +}; + +export const SubOrganization: Story = { + name: "Variant: Sub-Organization", + args: { + variant: "sub-org", + children: ( + <> + + Sub-Organization + + ) + }, + parameters: { + docs: { + description: { + story: "Use this variant when indicating sub-organization scope or links." + } + } + } +}; + +export const Project: Story = { + name: "Variant: Project", + args: { + variant: "project", + children: ( + <> + + Project + + ) + }, + parameters: { + docs: { + description: { + story: "Use this variant when indicating project scope or links." + } + } + } +}; + +export const AsExternalLink: Story = { + name: "Example: As External Link", + args: { + variant: "info", + asChild: true, + children: ( + + Link + + ) + }, + parameters: { + docs: { + description: { + story: "Use the `asChild` prop with an `a` tag to use a badge as an external link." + } + } + } +}; + +export const AsRouterLink: Story = { + name: "Example: As Router Link", + args: { + variant: "project", + asChild: true, + children: ( + + + Secret Scanning + + ) + }, + parameters: { + docs: { + description: { + story: "Use the `asChild` prop with a `Link` component to use a badge as an internal link." + } + } + } +}; + +export const AsButton: Story = { + name: "Example: As Button", + args: { + variant: "org", + asChild: true, + children: ( + + ) + }, + parameters: { + docs: { + description: { + story: + "Use the `asChild` prop with a `button` tag to use a badge as a button. Do not use a styled `Button` component." + } + } + } +}; + +export const IsTruncatable: Story = { + name: "Example: isTruncatable", + args: { + isTruncatable: true, + children: ( + <> + + Infisical Infrastructure + + ) + }, + parameters: { + docs: { + description: { + story: + "Use the `isTruncatable` prop with a `span` tag wrapping the text content to support truncation." + } + } + }, + decorators: (Story) => ( +

- + @@ -286,32 +317,34 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { )} - - {(isAllowed) => ( - - handlePopUpOpen("certificate", { - serialNumber: certificate.serialNumber - }) - } - disabled={!isAllowed} - icon={} - > - View Details - - )} - + {isLegacyTemplatesEnabled && ( + + {(isAllowed) => ( + + handlePopUpOpen("certificate", { + serialNumber: certificate.serialNumber + }) + } + disabled={!isAllowed} + icon={} + > + View Details + + )} + + )} {/* Manage auto renewal option - not shown for failed renewals */} {(() => { const canManageRenewal = certificate.profileId && - !certificate.renewedById && + !certificate.renewedByCertificateId && !isRevoked && !isExpired && !hasFailed && @@ -353,8 +386,9 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { ttlDays, notAfter: certificate.notAfter, renewalError: certificate.renewalError, - renewedFromId: certificate.renewedFromId, - renewedById: certificate.renewedById + renewedFromCertificateId: + certificate.renewedFromCertificateId, + renewedByCertificateId: certificate.renewedByCertificateId }); }} disabled={!isAllowed} @@ -373,7 +407,7 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { {(() => { const canDisableRenewal = certificate.profileId && - !certificate.renewedById && + !certificate.renewedByCertificateId && !isRevoked && !isExpired && !isExpiringWithinDay && @@ -411,7 +445,7 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { {(() => { const canRenew = certificate.profileId && - !certificate.renewedById && + !certificate.renewedByCertificateId && !isRevoked && !isExpired; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/useCertificateTemplate.ts b/frontend/src/pages/cert-manager/CertificatesPage/components/useCertificateTemplate.ts index 871ad00a4..5499a2762 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/useCertificateTemplate.ts +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/useCertificateTemplate.ts @@ -11,6 +11,26 @@ import { mapTemplateSignatureAlgorithmToApi } from "@app/pages/cert-manager/PoliciesPage/components/CertificateTemplatesV2Tab/shared/certificate-constants"; +const convertTemplateTtlToCertificateTtl = (templateTtl: string): string => { + const match = templateTtl.match(/^(\d+)([dmyh])$/); + if (!match) return templateTtl; + + const [, value, unit] = match; + const numValue = parseInt(value, 10); + + switch (unit) { + case "m": + return `${numValue * 30}d`; + case "y": + return `${numValue * 365}d`; + case "d": + case "h": + return templateTtl; + default: + return templateTtl; + } +}; + export type TemplateConstraints = { allowedKeyUsages: string[]; allowedExtendedKeyUsages: string[]; @@ -118,7 +138,7 @@ export const useCertificateTemplate = ( // Set TTL if available if (templateData.validity?.max) { - setValue("ttl", templateData.validity.max); + setValue("ttl", convertTemplateTtlToCertificateTtl(templateData.validity.max)); } // Handle SAN types From 525568683ff18d0f391fca38522daa7bb0a75ec7 Mon Sep 17 00:00:00 2001 From: x032205 Date: Fri, 24 Oct 2025 05:42:43 -0400 Subject: [PATCH 108/146] add a toggle for resource account rotation --- .../shared/sql-account-schemas.ts | 28 ----- .../PamResourceForm/PostgresResourceForm.tsx | 4 +- .../shared/SqlRotateAccountFields.tsx | 111 +++++++++++------- 3 files changed, 70 insertions(+), 73 deletions(-) diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas.ts b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas.ts index 751277254..37efd67d4 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas.ts +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas.ts @@ -12,31 +12,3 @@ export const BaseSqlAccountSchema = z.object({ .min(1, "Password required") .max(256, "Password must be 256 characters or less") }); - -export const BaseSqlRotationAccountSchema = z - .object({ - username: z.string().trim().max(63, "Username must be 63 characters or less"), - password: z.string().trim().max(256, "Password must be 256 characters or less") - }) - .superRefine((data, ctx) => { - if (data.username && !data.password) { - ctx.addIssue({ - path: ["password"], - message: "Password is required", - code: z.ZodIssueCode.custom - }); - } - if (data.password && !data.username) { - ctx.addIssue({ - path: ["username"], - message: "Username is required", - code: z.ZodIssueCode.custom - }); - } - }) - .transform((val) => { - if (!val.username && !val.password) { - return null; - } - return val; - }); diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx index fbca7bc87..7e96fffda 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx @@ -6,7 +6,7 @@ import { z } from "zod"; import { Button, ModalClose } from "@app/components/v2"; import { PamResourceType, TPostgresResource } from "@app/hooks/api/pam"; import { UNCHANGED_PASSWORD_SENTINEL } from "@app/hooks/api/pam/constants"; -import { BaseSqlRotationAccountSchema } from "@app/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas"; +import { BaseSqlAccountSchema } from "@app/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas"; import { BaseSqlResourceSchema } from "./shared/sql-resource-schemas"; import { SqlResourceFields } from "./shared/SqlResourceFields"; @@ -21,7 +21,7 @@ type Props = { const formSchema = genericResourceFieldsSchema.extend({ resourceType: z.literal(PamResourceType.Postgres), connectionDetails: BaseSqlResourceSchema, - rotationAccountCredentials: BaseSqlRotationAccountSchema.nullable().optional() + rotationAccountCredentials: BaseSqlAccountSchema.nullable().optional() }); type FormData = z.infer; diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx index c3a98a3f6..d3f11ed60 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx @@ -1,40 +1,74 @@ import { useEffect, useState } from "react"; import { Controller, useFormContext, useWatch } from "react-hook-form"; -import { faTimes } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { - Accordion, - AccordionContent, - AccordionItem, - AccordionTrigger, - FormControl, - Input -} from "@app/components/v2"; +import { FormControl, Input, Switch } from "@app/components/v2"; import { UNCHANGED_PASSWORD_SENTINEL } from "@app/hooks/api/pam/constants"; export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { - const { control } = useFormContext(); + const { control, setValue, getValues } = useFormContext(); const [showPassword, setShowPassword] = useState(false); const password = useWatch({ control, name: "credentials.password" }); + const rotationUsername = useWatch({ control, name: "rotationAccountCredentials.username" }); + const rotationPassword = useWatch({ control, name: "rotationAccountCredentials.password" }); + + const [enabled, setEnabled] = useState(false); + const [wasRotationPasswordSentinelInitially, setWasRotationPasswordSentinelInitially] = + useState(false); + + useEffect(() => { + const initialRotationPass = getValues("rotationAccountCredentials.password"); + if (initialRotationPass === UNCHANGED_PASSWORD_SENTINEL) { + setWasRotationPasswordSentinelInitially(true); + } + }, [getValues]); + useEffect(() => { if (password === UNCHANGED_PASSWORD_SENTINEL) { setShowPassword(false); } }, [password]); + useEffect(() => { + const isUsernamePopulated = rotationUsername && rotationUsername !== ""; + const isPasswordPopulated = + rotationPassword && + rotationPassword !== "" && + rotationPassword !== UNCHANGED_PASSWORD_SENTINEL; + + if (isUsernamePopulated || isPasswordPopulated) { + setEnabled(true); + } + }, [rotationUsername, rotationPassword]); + return ( - - - -
Rotation Account
-
- -

- Credentials of the privileged account which will be used for rotating other accounts - under this resource -

+
+ { + setEnabled(value); + if (value) { + setValue("rotationAccountCredentials.username", "", { + shouldDirty: true + }); + setValue("rotationAccountCredentials.password", "", { + shouldDirty: true + }); + } else { + setValue("rotationAccountCredentials", null, { + shouldDirty: true + }); + } + }} + isChecked={enabled} + containerClassName="flex-row-reverse w-fit" + className="ml-0" + > +

Credential Rotation

+
+ + {enabled && ( + <>
{ >
- {field.value && ( - - )}
)} @@ -83,28 +108,28 @@ export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { setShowPassword(true); }} onBlur={() => { - if (isUpdate && field.value === "") { + if ( + isUpdate && + field.value === "" && + wasRotationPasswordSentinelInitially + ) { field.onChange(UNCHANGED_PASSWORD_SENTINEL); } setShowPassword(false); }} /> - {field.value && ( - - )}
)} />
-
-
-
+ +

+ Credentials of the privileged account which will be used for rotating other accounts + under this resource +

+ + )} + ); }; From bcb0e8e705a176d2c30d09fa7e66e46b52042cfe Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Fri, 24 Oct 2025 15:53:38 +0400 Subject: [PATCH 109/146] fix: gateway improvements --- backend/src/lib/gateway-v2/gateway-v2.ts | 6 +++++- .../identity-kubernetes-auth-service.ts | 3 ++- .../templates/serviceaccount-token-reviewer.yaml | 14 ++++++++++++++ .../templates/serviceaccount.yaml | 1 + helm-charts/infisical-gateway/values.yaml | 1 + 5 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 helm-charts/infisical-gateway/templates/serviceaccount-token-reviewer.yaml diff --git a/backend/src/lib/gateway-v2/gateway-v2.ts b/backend/src/lib/gateway-v2/gateway-v2.ts index 5ae0e5b1d..46abe4bf1 100644 --- a/backend/src/lib/gateway-v2/gateway-v2.ts +++ b/backend/src/lib/gateway-v2/gateway-v2.ts @@ -7,6 +7,7 @@ import https from "https"; import { verifyHostInputValidity } from "@app/ee/services/dynamic-secret/dynamic-secret-fns"; import { splitPemChain } from "@app/services/certificate/certificate-fns"; +import { getConfig } from "../config/env"; import { BadRequestError } from "../errors"; import { GatewayProxyProtocol } from "../gateway/types"; import { logger } from "../logger"; @@ -80,6 +81,8 @@ const createGatewayConnection = async ( gateway: { clientCertificate: string; clientPrivateKey: string; serverCertificateChain: string }, protocol: GatewayProxyProtocol ): Promise => { + const appCfg = getConfig(); + const protocolToAlpn = { [GatewayProxyProtocol.Http]: "infisical-http-proxy", [GatewayProxyProtocol.Tcp]: "infisical-tcp-proxy", @@ -94,7 +97,8 @@ const createGatewayConnection = async ( minVersion: "TLSv1.2", maxVersion: "TLSv1.3", rejectUnauthorized: true, - ALPNProtocols: [protocolToAlpn[protocol]] + ALPNProtocols: [protocolToAlpn[protocol]], + checkServerIdentity: appCfg.isDevelopmentMode ? () => undefined : tls.checkServerIdentity }; return new Promise((resolve, reject) => { diff --git a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts index 49fb597f5..8a8fd5091 100644 --- a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts +++ b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts @@ -719,7 +719,8 @@ export const identityKubernetesAuthServiceFactory = ({ ); } - const shouldUpdateGatewayId = Boolean(gatewayId); + // Strict check to see if gateway ID is undefined. It should update the gateway ID to null if its strictly set to null. + const shouldUpdateGatewayId = Boolean(gatewayId !== undefined); const gatewayIdValue = isGatewayV1 ? gatewayId : null; const gatewayV2IdValue = isGatewayV1 ? null : gatewayId; diff --git a/helm-charts/infisical-gateway/templates/serviceaccount-token-reviewer.yaml b/helm-charts/infisical-gateway/templates/serviceaccount-token-reviewer.yaml new file mode 100644 index 000000000..e92352318 --- /dev/null +++ b/helm-charts/infisical-gateway/templates/serviceaccount-token-reviewer.yaml @@ -0,0 +1,14 @@ +{{- if and .Values.serviceAccount.createAsAuthDelegator .Values.serviceAccount.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "infisical-gateway.serviceAccountName" . }}-system-auth-delegator-cluster-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: + - kind: ServiceAccount + name: {{ include "infisical-gateway.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} \ No newline at end of file diff --git a/helm-charts/infisical-gateway/templates/serviceaccount.yaml b/helm-charts/infisical-gateway/templates/serviceaccount.yaml index c0040963f..1ed3d38d6 100644 --- a/helm-charts/infisical-gateway/templates/serviceaccount.yaml +++ b/helm-charts/infisical-gateway/templates/serviceaccount.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: ServiceAccount metadata: + namespace: {{ .Release.Namespace }} name: {{ include "infisical-gateway.serviceAccountName" . }} labels: {{- include "infisical-gateway.labels" . | nindent 4 }} diff --git a/helm-charts/infisical-gateway/values.yaml b/helm-charts/infisical-gateway/values.yaml index c792d67a6..dab76f6a0 100644 --- a/helm-charts/infisical-gateway/values.yaml +++ b/helm-charts/infisical-gateway/values.yaml @@ -21,6 +21,7 @@ fullnameOverride: "" serviceAccount: create: true automount: true + createAsAuthDelegator: true annotations: {} name: "" From d441e4197f2c1cc95bcff4101982a61c522d6e32 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Fri, 24 Oct 2025 16:00:41 +0400 Subject: [PATCH 110/146] fix: lint test --- .github/workflows/release_helm_gateway.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release_helm_gateway.yaml b/.github/workflows/release_helm_gateway.yaml index 7fd0eb03a..cfd29a56e 100644 --- a/.github/workflows/release_helm_gateway.yaml +++ b/.github/workflows/release_helm_gateway.yaml @@ -24,6 +24,8 @@ jobs: - name: Set up chart-testing uses: helm/chart-testing-action@v2.7.0 + with: + yamale_version: "6.0.0" - name: Run chart-testing (lint) run: ct lint --config ct.yaml --charts helm-charts/infisical-gateway From 579e2cae14f232c961db7da6540c540d2e060bf0 Mon Sep 17 00:00:00 2001 From: Victor Santos Date: Fri, 24 Oct 2025 09:52:29 -0300 Subject: [PATCH 111/146] feat(identity-aws-auth): support GovCloud ARNs in ARN extraction and validation --- .../src/services/identity-aws-auth/identity-aws-auth-fns.ts | 4 +++- .../identity-aws-auth/identity-aws-auth-validators.ts | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-fns.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-fns.ts index 38944917e..a028bc25f 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-fns.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-fns.ts @@ -83,9 +83,11 @@ export const extractPrincipalArnEntity = (arn: string, formatAsIamRole: boolean * Extracts the identity ARN from the GetCallerIdentity response to one of the following formats: * - arn:aws:iam::123456789012:user/MyUserName * - arn:aws:iam::123456789012:role/MyRoleName + * - arn:aws-us-gov:iam::123456789012:user/MyUserName (GovCloud) + * - arn:aws-us-gov:iam::123456789012:role/MyRoleName (GovCloud) */ export const extractPrincipalArn = (arn: string, formatAsIamRole: boolean = false) => { const entity = extractPrincipalArnEntity(arn, formatAsIamRole); - return `arn:aws:${formatAsIamRole ? "iam" : entity.Service}::${entity.AccountNumber}:${entity.Type}/${entity.FriendlyName}`; + return `arn:${entity.Partition}:${formatAsIamRole ? "iam" : entity.Service}::${entity.AccountNumber}:${entity.Type}/${entity.FriendlyName}`; }; diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts index 4e3884e15..ed7f6696a 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-validators.ts @@ -6,7 +6,7 @@ const twelveDigitRegex = new RE2(/^\d{12}$/); // akhilmhdh: change this to a normal function later. Checked no redosable at the moment const arnRegex = new RE2( - /^arn:aws:(iam|sts)::\d{12}:(user\/[a-zA-Z0-9_.@+*/-]+|role\/[a-zA-Z0-9_.@+*/-]+|assumed-role\/[a-zA-Z0-9_.@+*/-]+|\*)$/ + /^arn:aws(?:-us-gov)?:(iam|sts)::\d{12}:(user\/[a-zA-Z0-9_.@+*/-]+|role\/[a-zA-Z0-9_.@+*/-]+|assumed-role\/[a-zA-Z0-9_.@+*/-]+|\*)$/ ); export const validateAccountIds = z @@ -55,7 +55,7 @@ export const validatePrincipalArns = z }, { message: - "Each ARN must be in the format of 'arn:aws:iam::123456789012:user/UserName', 'arn:aws:iam::123456789012:role/RoleName', or 'arn:aws:iam::123456789012:*', 'arn:aws:sts::123456789012:assumed-role/RoleName'." + "Each ARN must be in the format of 'arn:aws:iam::123456789012:user/UserName', 'arn:aws:iam::123456789012:role/RoleName', or 'arn:aws:iam::123456789012:*', 'arn:aws:sts::123456789012:assumed-role/RoleName'. GovCloud ARNs (arn:aws-us-gov:...) are also supported." } ) // Transform to normalize the spaces around commas From 096bdec439df881798c8aabf7992666e5aff1aa2 Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Fri, 24 Oct 2025 19:52:05 +0530 Subject: [PATCH 112/146] feat: adds PAT support to github integration --- .../app-connection/app-connection-fns.ts | 2 + .../github/github-connection-enums.ts | 3 +- .../github/github-connection-fns.ts | 45 +++++++++- .../github/github-connection-schemas.ts | 49 ++++++++++- .../secret-sync/github/github-sync-fns.ts | 32 +++++-- frontend/src/helpers/appConnections.ts | 2 + .../appConnections/types/github-connection.ts | 11 ++- .../AppConnectionForm/AppConnectionForm.tsx | 8 +- .../GitHubConnectionForm.tsx | 88 +++++++++++++++---- 9 files changed, 205 insertions(+), 35 deletions(-) diff --git a/backend/src/services/app-connection/app-connection-fns.ts b/backend/src/services/app-connection/app-connection-fns.ts index 464f718ce..21989c6ae 100644 --- a/backend/src/services/app-connection/app-connection-fns.ts +++ b/backend/src/services/app-connection/app-connection-fns.ts @@ -345,6 +345,8 @@ export const getAppConnectionMethodName = (method: TAppConnection["method"]) => case GitHubConnectionMethod.App: case GitHubRadarConnectionMethod.App: return "GitHub App"; + case GitHubConnectionMethod.Pat: + return "Personal Access Token"; case AzureKeyVaultConnectionMethod.OAuth: case AzureAppConfigurationConnectionMethod.OAuth: case AzureClientSecretsConnectionMethod.OAuth: diff --git a/backend/src/services/app-connection/github/github-connection-enums.ts b/backend/src/services/app-connection/github/github-connection-enums.ts index 77a4eebac..18dac354f 100644 --- a/backend/src/services/app-connection/github/github-connection-enums.ts +++ b/backend/src/services/app-connection/github/github-connection-enums.ts @@ -1,4 +1,5 @@ export enum GitHubConnectionMethod { OAuth = "oauth", - App = "github-app" + App = "github-app", + Pat = "pat" } diff --git a/backend/src/services/app-connection/github/github-connection-fns.ts b/backend/src/services/app-connection/github/github-connection-fns.ts index 5cbf5c60d..806df039f 100644 --- a/backend/src/services/app-connection/github/github-connection-fns.ts +++ b/backend/src/services/app-connection/github/github-connection-fns.ts @@ -248,10 +248,18 @@ export const makePaginatedGitHubRequest = async ( ): Promise => { const { credentials, method } = appConnection; - const token = - method === GitHubConnectionMethod.OAuth - ? credentials.accessToken - : await getGitHubAppAuthToken(appConnection, gatewayService, gatewayV2Service); + let token: string; + + switch (method) { + case GitHubConnectionMethod.OAuth: + token = credentials.accessToken; + break; + case GitHubConnectionMethod.Pat: + token = credentials.personalAccessToken; + break; + default: + token = await getGitHubAppAuthToken(appConnection, gatewayService, gatewayV2Service); + } const baseUrl = `https://${await getGitHubInstanceApiUrl(appConnection)}${path}`; const initialUrlObj = new URL(baseUrl); @@ -460,6 +468,35 @@ export const validateGitHubConnectionCredentials = async ( gatewayV2Service: Pick ) => { const { credentials, method } = config; + + // PAT validation + if (method === GitHubConnectionMethod.Pat) { + try { + const apiUrl = await getGitHubInstanceApiUrl(config); + await requestWithGitHubGateway(config, gatewayService, gatewayV2Service, { + url: `https://${apiUrl}/user`, + method: "GET", + headers: { + Accept: "application/vnd.github+json", + Authorization: `Bearer ${credentials.personalAccessToken}`, + "X-GitHub-Api-Version": "2022-11-28" + } + }); + + return { + personalAccessToken: credentials.personalAccessToken, + instanceType: credentials.instanceType, + host: credentials.host + }; + } catch (e: unknown) { + logger.error(e, "Unable to verify GitHub PAT connection"); + + throw new BadRequestError({ + message: "Unable to validate Personal Access Token: verify token has proper permissions" + }); + } + } + const { INF_APP_CONNECTION_GITHUB_OAUTH_CLIENT_ID, INF_APP_CONNECTION_GITHUB_OAUTH_CLIENT_SECRET, diff --git a/backend/src/services/app-connection/github/github-connection-schemas.ts b/backend/src/services/app-connection/github/github-connection-schemas.ts index 1b8aa9c3f..20ef2c0e0 100644 --- a/backend/src/services/app-connection/github/github-connection-schemas.ts +++ b/backend/src/services/app-connection/github/github-connection-schemas.ts @@ -38,6 +38,19 @@ export const GitHubConnectionAppInputCredentialsSchema = z.union([ }) ]); +export const GitHubConnectionPatInputCredentialsSchema = z.union([ + z.object({ + personalAccessToken: z.string().trim().min(1, "Personal Access Token required"), + instanceType: z.literal("server"), + host: z.string().trim().min(1, "Host is required for server instance type") + }), + z.object({ + personalAccessToken: z.string().trim().min(1, "Personal Access Token required"), + instanceType: z.literal("cloud").optional(), + host: z.string().trim().optional() + }) +]); + export const GitHubConnectionOAuthOutputCredentialsSchema = z.union([ z.object({ accessToken: z.string(), @@ -64,6 +77,19 @@ export const GitHubConnectionAppOutputCredentialsSchema = z.union([ }) ]); +export const GitHubConnectionPatOutputCredentialsSchema = z.union([ + z.object({ + personalAccessToken: z.string(), + instanceType: z.literal("server"), + host: z.string().trim().min(1) + }), + z.object({ + personalAccessToken: z.string(), + instanceType: z.literal("cloud").optional(), + host: z.string().trim().optional() + }) +]); + export const ValidateGitHubConnectionCredentialsSchema = z.discriminatedUnion("method", [ z.object({ method: z.literal(GitHubConnectionMethod.App).describe(AppConnections.CREATE(AppConnection.GitHub).method), @@ -76,6 +102,12 @@ export const ValidateGitHubConnectionCredentialsSchema = z.discriminatedUnion("m credentials: GitHubConnectionOAuthInputCredentialsSchema.describe( AppConnections.CREATE(AppConnection.GitHub).credentials ) + }), + z.object({ + method: z.literal(GitHubConnectionMethod.Pat).describe(AppConnections.CREATE(AppConnection.GitHub).method), + credentials: GitHubConnectionPatInputCredentialsSchema.describe( + AppConnections.CREATE(AppConnection.GitHub).credentials + ) }) ]); @@ -88,7 +120,11 @@ export const CreateGitHubConnectionSchema = ValidateGitHubConnectionCredentialsS export const UpdateGitHubConnectionSchema = z .object({ credentials: z - .union([GitHubConnectionAppInputCredentialsSchema, GitHubConnectionOAuthInputCredentialsSchema]) + .union([ + GitHubConnectionAppInputCredentialsSchema, + GitHubConnectionOAuthInputCredentialsSchema, + GitHubConnectionPatInputCredentialsSchema + ]) .optional() .describe(AppConnections.UPDATE(AppConnection.GitHub).credentials) }) @@ -110,6 +146,10 @@ export const GitHubConnectionSchema = z.intersection( z.object({ method: z.literal(GitHubConnectionMethod.OAuth), credentials: GitHubConnectionOAuthOutputCredentialsSchema + }), + z.object({ + method: z.literal(GitHubConnectionMethod.Pat), + credentials: GitHubConnectionPatOutputCredentialsSchema }) ]) ); @@ -128,6 +168,13 @@ export const SanitizedGitHubConnectionSchema = z.discriminatedUnion("method", [ instanceType: z.union([z.literal("server"), z.literal("cloud")]).optional(), host: z.string().optional() }) + }), + BaseGitHubConnectionSchema.extend({ + method: z.literal(GitHubConnectionMethod.Pat), + credentials: z.object({ + instanceType: z.union([z.literal("server"), z.literal("cloud")]).optional(), + host: z.string().optional() + }) }) ]); diff --git a/backend/src/services/secret-sync/github/github-sync-fns.ts b/backend/src/services/secret-sync/github/github-sync-fns.ts index 4b174ca2a..e7116d604 100644 --- a/backend/src/services/secret-sync/github/github-sync-fns.ts +++ b/backend/src/services/secret-sync/github/github-sync-fns.ts @@ -211,10 +211,18 @@ export const GithubSyncFns = { } const { connection } = secretSync; - const token = - connection.method === GitHubConnectionMethod.OAuth - ? connection.credentials.accessToken - : await getGitHubAppAuthToken(connection, gatewayService, gatewayV2Service); + let token: string; + + switch (connection.method) { + case GitHubConnectionMethod.OAuth: + token = connection.credentials.accessToken; + break; + case GitHubConnectionMethod.Pat: + token = connection.credentials.personalAccessToken; + break; + default: + token = await getGitHubAppAuthToken(connection, gatewayService, gatewayV2Service); + } const encryptedSecrets = await getEncryptedSecrets(secretSync, gatewayService, gatewayV2Service); const publicKey = await getPublicKey(secretSync, gatewayService, gatewayV2Service, token); @@ -269,10 +277,18 @@ export const GithubSyncFns = { const secretMap = Object.fromEntries(Object.entries(ogSecretMap).map(([i, v]) => [i.toUpperCase(), v])); const { connection } = secretSync; - const token = - connection.method === GitHubConnectionMethod.OAuth - ? connection.credentials.accessToken - : await getGitHubAppAuthToken(connection, gatewayService, gatewayV2Service); + let token: string; + + switch (connection.method) { + case GitHubConnectionMethod.OAuth: + token = connection.credentials.accessToken; + break; + case GitHubConnectionMethod.Pat: + token = connection.credentials.personalAccessToken; + break; + default: + token = await getGitHubAppAuthToken(connection, gatewayService, gatewayV2Service); + } const encryptedSecrets = await getEncryptedSecrets(secretSync, gatewayService, gatewayV2Service); diff --git a/frontend/src/helpers/appConnections.ts b/frontend/src/helpers/appConnections.ts index bdb26c796..9ee03c3c0 100644 --- a/frontend/src/helpers/appConnections.ts +++ b/frontend/src/helpers/appConnections.ts @@ -135,6 +135,8 @@ export const getAppConnectionMethodDetails = (method: TAppConnection["method"]) case GitHubConnectionMethod.App: case GitHubRadarConnectionMethod.App: return { name: "GitHub App", icon: faGithub }; + case GitHubConnectionMethod.Pat: + return { name: "Personal Access Token", icon: faKey }; case AzureKeyVaultConnectionMethod.OAuth: case AzureAppConfigurationConnectionMethod.OAuth: case AzureClientSecretsConnectionMethod.OAuth: diff --git a/frontend/src/hooks/api/appConnections/types/github-connection.ts b/frontend/src/hooks/api/appConnections/types/github-connection.ts index 27bed2dcb..595e5adbb 100644 --- a/frontend/src/hooks/api/appConnections/types/github-connection.ts +++ b/frontend/src/hooks/api/appConnections/types/github-connection.ts @@ -3,7 +3,8 @@ import { TRootAppConnection } from "@app/hooks/api/appConnections/types/root-con export enum GitHubConnectionMethod { App = "github-app", - OAuth = "oauth" + OAuth = "oauth", + Pat = "pat" } export type TGitHubConnection = TRootAppConnection & { app: AppConnection.GitHub } & ( @@ -24,4 +25,12 @@ export type TGitHubConnection = TRootAppConnection & { app: AppConnection.GitHub host?: string; }; } + | { + method: GitHubConnectionMethod.Pat; + credentials: { + personalAccessToken: string; + instanceType?: "cloud" | "server"; + host?: string; + }; + } ); diff --git a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/AppConnectionForm.tsx b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/AppConnectionForm.tsx index a44c4746b..c4115a4b7 100644 --- a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/AppConnectionForm.tsx +++ b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/AppConnectionForm.tsx @@ -96,7 +96,7 @@ const CreateForm = ({ app, onComplete, projectId }: CreateFormProps) => { case AppConnection.AWS: return ; case AppConnection.GitHub: - return ; + return ; case AppConnection.GitHubRadar: return ; case AppConnection.GCP: @@ -213,7 +213,11 @@ const UpdateForm = ({ appConnection, onComplete }: UpdateFormProps) => { return ; case AppConnection.GitHub: return ( - + ); case AppConnection.GitHubRadar: return ( diff --git a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/GitHubConnectionForm.tsx b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/GitHubConnectionForm.tsx index 5faa7d5b0..2ec06c6b8 100644 --- a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/GitHubConnectionForm.tsx +++ b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/GitHubConnectionForm.tsx @@ -16,6 +16,7 @@ import { FormControl, Input, ModalClose, + SecretInput, Select, SelectItem, Tooltip @@ -48,28 +49,43 @@ import { type Props = { appConnection?: TGitHubConnection; projectId: string | undefined | null; + onSubmit: (formData: PatSchemaForm) => Promise; }; -const formSchema = genericAppConnectionFieldsSchema.extend({ +const rootSchema = genericAppConnectionFieldsSchema.extend({ app: z.literal(AppConnection.GitHub), - method: z.nativeEnum(GitHubConnectionMethod), - credentials: z - .union([ - z.object({ - instanceType: z.literal("cloud").optional(), - host: z.string().optional() - }), - z.object({ - instanceType: z.literal("server"), - host: z.string().min(1, "Required") - }) - ]) - .optional() + method: z.nativeEnum(GitHubConnectionMethod) }); +const baseCredentialsSchema = z.object({ + instanceType: z.union([z.literal("cloud"), z.literal("server")]).optional(), + host: z.string().optional() +}); + +const appSchema = rootSchema.extend({ + method: z.literal(GitHubConnectionMethod.App), + credentials: baseCredentialsSchema +}); + +const oauthSchema = rootSchema.extend({ + method: z.literal(GitHubConnectionMethod.OAuth), + credentials: baseCredentialsSchema +}); + +const patSchema = rootSchema.extend({ + method: z.literal(GitHubConnectionMethod.Pat), + credentials: baseCredentialsSchema.extend({ + personalAccessToken: z.string().min(1, "Personal Access Token is required") + }) +}); + +type PatSchemaForm = z.infer; + +const formSchema = z.discriminatedUnion("method", [appSchema, oauthSchema, patSchema]); + type FormData = z.infer; -export const GitHubConnectionForm = ({ appConnection, projectId }: Props) => { +export const GitHubConnectionForm = ({ appConnection, projectId, onSubmit }: Props) => { const isUpdate = Boolean(appConnection); const [isRedirecting, setIsRedirecting] = useState(false); @@ -106,7 +122,12 @@ export const GitHubConnectionForm = ({ appConnection, projectId }: Props) => { const returnUrl = useGetAppConnectionOauthReturnUrl(); - const onSubmit = (formData: FormData) => { + const submitHandler = async (formData: FormData) => { + if (formData.method === GitHubConnectionMethod.Pat) { + await onSubmit(formData); + return; + } + setIsRedirecting(true); const state = crypto.randomBytes(16).toString("hex"); localStorage.setItem("latestCSRFToken", state); @@ -151,15 +172,26 @@ export const GitHubConnectionForm = ({ appConnection, projectId }: Props) => { case GitHubConnectionMethod.App: isMissingConfig = !appClientSlug; break; + case GitHubConnectionMethod.Pat: + isMissingConfig = false; + break; default: throw new Error(`Unhandled GitHub Connection method: ${selectedMethod}`); } const methodDetails = getAppConnectionMethodDetails(selectedMethod); + const getButtonText = () => { + if (selectedMethod === GitHubConnectionMethod.Pat) { + return isUpdate ? "Update Connection" : "Create Connection"; + } + + return isUpdate ? "Reconnect to GitHub" : "Connect to GitHub"; + }; + return ( - + {!isUpdate && } { )} /> + {selectedMethod === GitHubConnectionMethod.Pat && ( + ( + + onChange(e.target.value)} + /> + + )} + /> + )} @@ -310,7 +362,7 @@ export const GitHubConnectionForm = ({ appConnection, projectId }: Props) => { isLoading={isSubmitting || isRedirecting} isDisabled={isSubmitting || (!isUpdate && !isDirty) || isMissingConfig || isRedirecting} > - {isUpdate ? "Reconnect to GitHub" : "Connect to GitHub"} + {getButtonText()}
+ + + + + + + ); +}; diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PamAccountForm.tsx b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PamAccountForm.tsx index 8b553e656..7a1c1658e 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PamAccountForm.tsx +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/PamAccountForm.tsx @@ -8,6 +8,7 @@ import { import { DiscriminativePick } from "@app/types"; import { PamAccountHeader } from "../PamAccountHeader"; +import { MySQLAccountForm } from "./MySQLAccountForm"; import { PostgresAccountForm } from "./PostgresAccountForm"; type FormProps = { @@ -72,6 +73,13 @@ const CreateForm = ({ resourceType={resourceType} /> ); + case PamResourceType.MySQL: + return ( + ); default: throw new Error(`Unhandled resource: ${resourceType}`); } @@ -110,6 +118,8 @@ const UpdateForm = ({ account, onComplete }: UpdateFormProps) => { switch (account.resource.resourceType) { case PamResourceType.Postgres: return ; + case PamResourceType.MySQL: + return ; default: throw new Error(`Unhandled resource: ${account.resource.resourceType}`); } diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/MySQLResourceForm.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/MySQLResourceForm.tsx new file mode 100644 index 000000000..b7c2996d3 --- /dev/null +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/MySQLResourceForm.tsx @@ -0,0 +1,84 @@ +import { useState } from "react"; +import { FormProvider, useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; + +import { Button, ModalClose } from "@app/components/v2"; +import { PamResourceType, TMySQLResource } from "@app/hooks/api/pam"; + +import { BaseSqlResourceSchema } from "./shared/sql-resource-schemas"; +import { SqlResourceFields } from "./shared/SqlResourceFields"; +import { GenericResourceFields, genericResourceFieldsSchema } from "./GenericResourceFields"; + +type Props = { + resource?: TMySQLResource; + onSubmit: (formData: FormData) => Promise; +}; + +const formSchema = genericResourceFieldsSchema.extend({ + resourceType: z.literal(PamResourceType.MySQL), + connectionDetails: BaseSqlResourceSchema.extend({ + database: z.string().trim().optional().default("") + }) +}); + +type FormData = z.infer; + +export const MySQLResourceForm = ({ resource, onSubmit }: Props) => { + const isUpdate = Boolean(resource); + const [selectedTabIndex, setSelectedTabIndex] = useState(0); + + const form = useForm({ + resolver: zodResolver(formSchema), + defaultValues: resource ?? { + resourceType: PamResourceType.MySQL, + connectionDetails: { + host: "", + port: 3306, + database: "", + sslEnabled: true, + sslRejectUnauthorized: true, + sslCertificate: undefined + } + } + }); + + const { + handleSubmit, + formState: { isSubmitting, isDirty } + } = form; + + return ( + +
{ + setSelectedTabIndex(0); + handleSubmit(onSubmit)(e); + }} + > + + +
+ + + + +
+ +
+ ); +}; diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PamResourceForm.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PamResourceForm.tsx index 8cfdc8582..2bc54e7cd 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PamResourceForm.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PamResourceForm.tsx @@ -9,6 +9,7 @@ import { import { DiscriminativePick } from "@app/types"; import { PamResourceHeader } from "../PamResourceHeader"; +import { MySQLResourceForm } from "./MySQLResourceForm"; import { PostgresResourceForm } from "./PostgresResourceForm"; type FormProps = { @@ -57,6 +58,8 @@ const CreateForm = ({ resourceType, onComplete, projectId }: CreateFormProps) => switch (resourceType) { case PamResourceType.Postgres: return ; + case PamResourceType.MySQL: + return ; default: throw new Error(`Unhandled resource: ${resourceType}`); } @@ -92,8 +95,10 @@ const UpdateForm = ({ resource, onComplete }: UpdateFormProps) => { switch (resource.resourceType) { case PamResourceType.Postgres: return ; + case PamResourceType.MySQL: + return ; default: - throw new Error(`Unhandled resource: ${resource.resourceType}`); + throw new Error(`Unhandled resource: ${(resource as any).resourceType}`); } }; diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlResourceFields.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlResourceFields.tsx index 888b62984..c3f3982ec 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlResourceFields.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlResourceFields.tsx @@ -110,7 +110,7 @@ export const SqlResourceFields = ({ setSelectedTabIndex, selectedTabIndex }: Pro errorText={error?.message} isError={Boolean(error?.message)} className={sslEnabled ? "" : "opacity-50"} - label="SSL Certificate" + label="Trusted CA SSL Certificate" isOptional >
Status Not Before Not AfterAuto Renewal
{certificate.commonName} + {autoRenewalInfo && + (autoRenewalInfo.tooltip ? ( +
+ + {autoRenewalInfo.text} + + + + +
+ ) : ( + {autoRenewalInfo.text} + ))} +
@@ -172,10 +295,154 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { )} + {/* Manage auto renewal option - not shown for failed renewals */} + {(() => { + const isRevoked = certificate.status === CertStatus.REVOKED; + const isExpired = new Date(certificate.notAfter) < new Date(); + const hasFailed = Boolean(certificate.renewalError); + const isExpiringWithinDay = isExpiringWithinOneDay(certificate.notAfter); + const canManageRenewal = + certificate.profileId && + !certificate.renewedById && + !isRevoked && + !isExpired && + !hasFailed && + !isExpiringWithinDay; + + if (!canManageRenewal) return null; + + return ( + + {(isAllowed) => { + const isAutoRenewalEnabled = Boolean( + certificate.renewBeforeDays && certificate.renewBeforeDays > 0 + ); + + return ( + { + const notAfterDate = new Date(certificate.notAfter); + const notBeforeDate = new Date(certificate.notBefore); + const ttlDays = Math.ceil( + (notAfterDate.getTime() - notBeforeDate.getTime()) / + (24 * 60 * 60 * 1000) + ); + handlePopUpOpen("manageRenewal", { + certificateId: certificate.id, + commonName: certificate.commonName, + profileId: certificate.profileId, + renewBeforeDays: certificate.renewBeforeDays, + ttlDays, + notAfter: certificate.notAfter, + renewalError: certificate.renewalError, + renewedFromId: certificate.renewedFromId, + renewedById: certificate.renewedById + }); + }} + disabled={!isAllowed} + icon={} + > + {isAutoRenewalEnabled + ? "Manage auto renewal" + : "Enable auto renewal"} + + ); + }} + + ); + })()} + {/* Disable auto renewal option - only shown when auto renewal is active */} + {(() => { + const isRevoked = certificate.status === CertStatus.REVOKED; + const isExpired = new Date(certificate.notAfter) < new Date(); + const isExpiringWithinDay = isExpiringWithinOneDay(certificate.notAfter); + const isAutoRenewalEnabled = Boolean( + certificate.renewBeforeDays && certificate.renewBeforeDays > 0 + ); + const canDisableRenewal = + certificate.profileId && + !certificate.renewedById && + !isRevoked && + !isExpired && + !isExpiringWithinDay && + isAutoRenewalEnabled; + + if (!canDisableRenewal) return null; + + return ( + + {(isAllowed) => ( + { + await handleDisableAutoRenewal( + certificate.id, + certificate.commonName + ); + }} + disabled={!isAllowed} + icon={} + > + Disable auto renewal + + )} + + ); + })()} + {/* Manual renewal action for profile-issued certificates that are not revoked/expired (including failed ones) */} + {(() => { + const isRevoked = certificate.status === CertStatus.REVOKED; + const isExpired = new Date(certificate.notAfter) < new Date(); + const canRenew = + certificate.profileId && + !certificate.renewedById && + !isRevoked && + !isExpired; + + if (!canRenew) return null; + + return ( + + {(isAllowed) => ( + { + handlePopUpOpen("renewCertificate", { + certificateId: certificate.id, + commonName: certificate.commonName + }); + }} + disabled={!isAllowed} + icon={} + > + Renew Now + + )} + + ); + })()} {/* Only show revoke button if CA supports revocation */} {(() => { const caType = caCapabilityMap[certificate.caId]; - // If caId not found in map, assume CA supports revocation to avoid hiding revoke option const supportsRevocation = !caType || caSupportsCapability(caType, CaCapability.REVOKE_CERTIFICATES); diff --git a/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateProfilesTab/CreateProfileModal.tsx b/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateProfilesTab/CreateProfileModal.tsx index 3f7553f83..ea82fd843 100644 --- a/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateProfilesTab/CreateProfileModal.tsx +++ b/frontend/src/pages/cert-manager/PoliciesPage/components/CertificateProfilesTab/CreateProfileModal.tsx @@ -1,5 +1,7 @@ import { useEffect } from "react"; import { Controller, useForm } from "react-hook-form"; +import { faQuestionCircle } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; @@ -13,7 +15,8 @@ import { ModalContent, Select, SelectItem, - TextArea + TextArea, + Tooltip } from "@app/components/v2"; import { useProject } from "@app/context"; import { useListCasByProjectId } from "@app/hooks/api/ca/queries"; @@ -67,7 +70,7 @@ const createSchema = z apiConfig: z .object({ autoRenew: z.boolean().optional(), - autoRenewDays: z.number().min(1).max(365).optional() + renewBeforeDays: z.number().min(1).max(365).optional() }) .optional() }) @@ -115,7 +118,7 @@ const editSchema = z apiConfig: z .object({ autoRenew: z.boolean().optional(), - autoRenewDays: z.number().min(1).max(365).optional() + renewBeforeDays: z.number().min(1).max(365).optional() }) .optional() }) @@ -183,7 +186,7 @@ export const CreateProfileModal = ({ isOpen, onClose, profile, mode = "create" } profile.enrollmentType === "api" ? { autoRenew: profile.apiConfig?.autoRenew || false, - autoRenewDays: profile.apiConfig?.autoRenewDays || 30 + renewBeforeDays: profile.apiConfig?.renewBeforeDays || 30 } : undefined } @@ -195,7 +198,7 @@ export const CreateProfileModal = ({ isOpen, onClose, profile, mode = "create" } certificateTemplateId: "", apiConfig: { autoRenew: false, - autoRenewDays: 30 + renewBeforeDays: 30 } } }); @@ -225,7 +228,7 @@ export const CreateProfileModal = ({ isOpen, onClose, profile, mode = "create" } profile.enrollmentType === "api" ? { autoRenew: profile.apiConfig?.autoRenew || false, - autoRenewDays: profile.apiConfig?.autoRenewDays || 30 + renewBeforeDays: profile.apiConfig?.renewBeforeDays || 30 } : undefined }); @@ -389,7 +392,7 @@ export const CreateProfileModal = ({ isOpen, onClose, profile, mode = "create" } } else { setValue("apiConfig", { autoRenew: false, - autoRenewDays: 30 + renewBeforeDays: 30 }); setValue("estConfig", undefined); } @@ -433,7 +436,7 @@ export const CreateProfileModal = ({ isOpen, onClose, profile, mode = "create" } setValue("estConfig", undefined); setValue("apiConfig", { autoRenew: false, - autoRenewDays: 30 + renewBeforeDays: 30 }); } onChange(value); @@ -535,9 +538,18 @@ export const CreateProfileModal = ({ isOpen, onClose, profile, mode = "create" } name="apiConfig.autoRenew" render={({ field: { value, onChange }, fieldState: { error } }) => ( - - Enable Auto-Renewal - +
+ + Enable Auto-Renewal By Default + + + + +
)} /> @@ -548,10 +560,10 @@ export const CreateProfileModal = ({ isOpen, onClose, profile, mode = "create" }
( From 4cdb8cf4c57aa82abfb43651bd2b9f968903a24d Mon Sep 17 00:00:00 2001 From: x032205 Date: Wed, 22 Oct 2025 23:40:30 -0400 Subject: [PATCH 075/146] fix: allow rotation account credentials to be removed from resources --- backend/src/lib/config/env.ts | 2 +- .../shared/sql-account-schemas.ts | 28 +++++++++ .../PamResourceForm/PostgresResourceForm.tsx | 4 +- .../shared/SqlRotateAccountFields.tsx | 60 +++++++++++++------ 4 files changed, 73 insertions(+), 21 deletions(-) diff --git a/backend/src/lib/config/env.ts b/backend/src/lib/config/env.ts index 2da7a245a..9fc4cff92 100644 --- a/backend/src/lib/config/env.ts +++ b/backend/src/lib/config/env.ts @@ -3,13 +3,13 @@ import { z } from "zod"; import { THsmServiceFactory } from "@app/ee/services/hsm/hsm-service"; import { crypto } from "@app/lib/crypto/cryptography"; import { QueueWorkerProfile } from "@app/lib/types"; +import { TKmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal"; import { TSuperAdminDALFactory } from "@app/services/super-admin/super-admin-dal"; import { BadRequestError } from "../errors"; import { removeTrailingSlash } from "../fn"; import { CustomLogger } from "../logger/logger"; import { zpStr } from "../zod"; -import { TKmsRootConfigDALFactory } from "@app/services/kms/kms-root-config-dal"; export const GITLAB_URL = "https://gitlab.com"; diff --git a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas.ts b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas.ts index 37efd67d4..751277254 100644 --- a/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas.ts +++ b/frontend/src/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas.ts @@ -12,3 +12,31 @@ export const BaseSqlAccountSchema = z.object({ .min(1, "Password required") .max(256, "Password must be 256 characters or less") }); + +export const BaseSqlRotationAccountSchema = z + .object({ + username: z.string().trim().max(63, "Username must be 63 characters or less"), + password: z.string().trim().max(256, "Password must be 256 characters or less") + }) + .superRefine((data, ctx) => { + if (data.username && !data.password) { + ctx.addIssue({ + path: ["password"], + message: "Password is required", + code: z.ZodIssueCode.custom + }); + } + if (data.password && !data.username) { + ctx.addIssue({ + path: ["username"], + message: "Username is required", + code: z.ZodIssueCode.custom + }); + } + }) + .transform((val) => { + if (!val.username && !val.password) { + return null; + } + return val; + }); diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx index 7e96fffda..fbca7bc87 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/PostgresResourceForm.tsx @@ -6,7 +6,7 @@ import { z } from "zod"; import { Button, ModalClose } from "@app/components/v2"; import { PamResourceType, TPostgresResource } from "@app/hooks/api/pam"; import { UNCHANGED_PASSWORD_SENTINEL } from "@app/hooks/api/pam/constants"; -import { BaseSqlAccountSchema } from "@app/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas"; +import { BaseSqlRotationAccountSchema } from "@app/pages/pam/PamAccountsPage/components/PamAccountForm/shared/sql-account-schemas"; import { BaseSqlResourceSchema } from "./shared/sql-resource-schemas"; import { SqlResourceFields } from "./shared/SqlResourceFields"; @@ -21,7 +21,7 @@ type Props = { const formSchema = genericResourceFieldsSchema.extend({ resourceType: z.literal(PamResourceType.Postgres), connectionDetails: BaseSqlResourceSchema, - rotationAccountCredentials: BaseSqlAccountSchema.nullable().optional() + rotationAccountCredentials: BaseSqlRotationAccountSchema.nullable().optional() }); type FormData = z.infer; diff --git a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx index e7e9023dd..c3a98a3f6 100644 --- a/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx +++ b/frontend/src/pages/pam/PamResourcesPage/components/PamResourceForm/shared/SqlRotateAccountFields.tsx @@ -1,5 +1,7 @@ import { useEffect, useState } from "react"; import { Controller, useFormContext, useWatch } from "react-hook-form"; +import { faTimes } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Accordion, @@ -44,7 +46,18 @@ export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { isError={Boolean(error?.message)} label="Username" > - +
+ + {field.value && ( + + )} +
)} /> @@ -58,23 +71,34 @@ export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { isError={Boolean(error?.message)} label="Password" > - { - if (isUpdate && field.value === UNCHANGED_PASSWORD_SENTINEL) { - field.onChange(""); - } - setShowPassword(true); - }} - onBlur={() => { - if (isUpdate && field.value === "") { - field.onChange(UNCHANGED_PASSWORD_SENTINEL); - } - setShowPassword(false); - }} - /> +
+ { + if (isUpdate && field.value === UNCHANGED_PASSWORD_SENTINEL) { + field.onChange(""); + } + setShowPassword(true); + }} + onBlur={() => { + if (isUpdate && field.value === "") { + field.onChange(UNCHANGED_PASSWORD_SENTINEL); + } + setShowPassword(false); + }} + /> + {field.value && ( + + )} +
)} /> From edbfd7428265cb31d2a2f6655f7945da861904b0 Mon Sep 17 00:00:00 2001 From: x032205 Date: Thu, 23 Oct 2025 03:01:59 -0400 Subject: [PATCH 076/146] docs: add EC2 terraform deployment docs for relay --- docs/docs.json | 8 +- .../cli.mdx} | 4 +- .../gateways/relay-deployment/terraform.mdx | 150 ++++++++++++++++++ 3 files changed, 159 insertions(+), 3 deletions(-) rename docs/documentation/platform/gateways/{relay-deployment.mdx => relay-deployment/cli.mdx} (99%) create mode 100644 docs/documentation/platform/gateways/relay-deployment/terraform.mdx diff --git a/docs/docs.json b/docs/docs.json index 46f5aaf70..3bcc8ed89 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -176,7 +176,13 @@ "pages": [ "documentation/platform/gateways/overview", "documentation/platform/gateways/gateway-deployment", - "documentation/platform/gateways/relay-deployment", + { + "group": "Relay Deployment", + "pages": [ + "documentation/platform/gateways/relay-deployment/cli", + "documentation/platform/gateways/relay-deployment/terraform" + ] + }, "documentation/platform/gateways/security", { "group": "Gateway (Deprecated)", diff --git a/docs/documentation/platform/gateways/relay-deployment.mdx b/docs/documentation/platform/gateways/relay-deployment/cli.mdx similarity index 99% rename from docs/documentation/platform/gateways/relay-deployment.mdx rename to docs/documentation/platform/gateways/relay-deployment/cli.mdx index 767cf3732..5c16091a7 100644 --- a/docs/documentation/platform/gateways/relay-deployment.mdx +++ b/docs/documentation/platform/gateways/relay-deployment/cli.mdx @@ -1,6 +1,6 @@ --- -title: "Relay Deployment" -description: "How to deploy Infisical Relay Servers" +title: "CLI" +description: "How to deploy Infisical Relay Servers using the CLI" --- Infisical Relay is a secure routing layer that allows Infisical to connect to your private network resources, such as databases or internal APIs, without exposing them to the public internet. diff --git a/docs/documentation/platform/gateways/relay-deployment/terraform.mdx b/docs/documentation/platform/gateways/relay-deployment/terraform.mdx new file mode 100644 index 000000000..742ab602a --- /dev/null +++ b/docs/documentation/platform/gateways/relay-deployment/terraform.mdx @@ -0,0 +1,150 @@ +--- +title: "Terraform" +description: "How to deploy Infisical Relay Servers using Terraform" +--- + +This guide walks you through deploying an Infisical Relay server using Terraform. Select a provider below for specific instructions. + + + +The provided configuration automates the creation of the EC2 instance, sets up the necessary security group rules, and uses a startup script to install and configure the Infisical Relay service. + +### Prerequisites + +Before you start, make sure you have the following: +- An AWS account with permissions to create EC2 instances, Security Groups, and Elastic IPs. +- An existing VPC and Subnet ID in your desired AWS region. +- The AMI ID for your chosen OS (this guide uses an Ubuntu 22.04 LTS AMI). +- Credentials for the Infisical Relay to authenticate with your Infisical instance. This guide uses a Machine Identity token, but other methods are available. You can find a full list of authentication options [here](/cli/commands/relay#available-authentication-methods). + +### Terraform Configuration + +Here is the complete Terraform configuration to deploy the Infisical Relay. + +```terraform +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} + +provider "aws" { + region = "us-west-2" # Change to your desired AWS region +} + +# Security Group for the Infisical Relay instance +resource "aws_security_group" "infisical_relay_sg" { + name = "infisical-relay-sg" + description = "Allows inbound traffic for Infisical Relay and SSH" + vpc_id = "vpc-0c71f9c5709d88d18" # Change to your VPC ID + + # Inbound: Platform-to-relay communication (TLS) + ingress { + from_port = 8443 + to_port = 8443 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + # Inbound: SSH reverse tunnel from gateways + ingress { + from_port = 2222 + to_port = 2222 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + # Inbound: SSH access for administration + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] # Restrict this to your IP in production + } + + # Outbound: All traffic + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = "infisical-relay-sg" + } +} + +# Elastic IP for a static public IP address +resource "aws_eip" "infisical_relay_eip" { + tags = { + Name = "infisical-relay-eip" + } +} + +# EC2 instance to run Infisical Relay +module "infisical_relay_instance" { + source = "terraform-aws-modules/ec2-instance/aws" + version = "~> 5.6" + + name = "infisical-relay-example" + ami = "ami-065778886ef8ec7c8" # Change to your desired AMI ID + instance_type = "t3.micro" + subnet_id = "subnet-0fd2337a1c604a494" # Change to your Subnet ID + + vpc_security_group_ids = [aws_security_group.infisical_relay_sg.id] + associate_public_ip_address = false # We are using an Elastic IP instead + + user_data = <<-EOT + #!/bin/bash + set -e + # Install Infisical CLI + curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | bash + apt-get update && apt-get install -y infisical + + # Install the relay as a systemd service. + # This example uses a Machine Identity token for authentication (--token). + # For other authentication methods, see https://infisical.com/docs/cli/commands/relay#available-authentication-methods + sudo infisical relay systemd install \ + --token "your-machine-identity-token" \ + --name "my-relay-example" \ + --domain "https://app.infisical.com" \ # If you are self-hosting Infisical, change this to your instance's domain + --host "${aws_eip.infisical_relay_eip.public_ip}" + + # Start and enable the service to run on boot + sudo systemctl start infisical-relay + sudo systemctl enable infisical-relay + EOT +} + +# Associate the Elastic IP with the EC2 instance +resource "aws_eip_association" "eip_assoc" { + instance_id = module.infisical_relay_instance.id + allocation_id = aws_eip.infisical_relay_eip.id +} +``` + + +The provided security group rules are open to the internet (`0.0.0.0/0`) for simplicity. In a production environment, you should restrict the `cidr_blocks` to known IP addresses for enhanced security, especially for the SSH port (22). + + +### How to Deploy + +1. **Save the configuration:** Save the code above to a file named `main.tf`. +2. **Customize values:** Update the placeholder values in `main.tf` to match your AWS environment and Infisical credentials. You'll need to replace: + - `region` in the `provider` block. + - `vpc_id` in the `aws_security_group` resource. + - `ami` and `subnet_id` in the `infisical_relay_instance` module. + - The authentication flag and value in the `user_data` script (e.g., `--token "your-machine-identity-token"`). + - The `--domain` in the `user_data` script if you are self-hosting Infisical. +3. **Apply the configuration:** Run the following Terraform commands in your terminal: + ```bash + terraform init + terraform plan + terraform apply + ``` + + From cb5c7c57afd8a0ba712113bda813da2db47b5219 Mon Sep 17 00:00:00 2001 From: x032205 Date: Thu, 23 Oct 2025 03:05:17 -0400 Subject: [PATCH 077/146] greptile review fix --- .../platform/gateways/relay-deployment/terraform.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/documentation/platform/gateways/relay-deployment/terraform.mdx b/docs/documentation/platform/gateways/relay-deployment/terraform.mdx index 742ab602a..e2f13e228 100644 --- a/docs/documentation/platform/gateways/relay-deployment/terraform.mdx +++ b/docs/documentation/platform/gateways/relay-deployment/terraform.mdx @@ -111,7 +111,7 @@ module "infisical_relay_instance" { sudo infisical relay systemd install \ --token "your-machine-identity-token" \ --name "my-relay-example" \ - --domain "https://app.infisical.com" \ # If you are self-hosting Infisical, change this to your instance's domain + --domain "https://app.infisical.com" \ --host "${aws_eip.infisical_relay_eip.public_ip}" # Start and enable the service to run on boot From 91a183fa2549d81e1d996f3382b3970faede74ca Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 23 Oct 2025 12:22:29 +0400 Subject: [PATCH 078/146] Update login.mdx --- docs/cli/commands/login.mdx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/cli/commands/login.mdx b/docs/cli/commands/login.mdx index 9cfdc9645..4eeae76e0 100644 --- a/docs/cli/commands/login.mdx +++ b/docs/cli/commands/login.mdx @@ -84,7 +84,7 @@ User authentication is designed for individual developers and supports multiple infisical login --interactive ``` - + ```bash export INFISICAL_TOKEN=$(infisical login --email=user@example.com --password=your-password --plain --silent) ``` @@ -504,13 +504,10 @@ The following examples demonstrate different ways to authenticate as a user with #### Using Command-Line Flags ```bash - # Basic direct login + # Basic direct login (defaults to US Cloud) infisical login --email user@example.com --password "your-password" - # With custom domain (US Cloud) - infisical login --email user@example.com --password "your-password" --domain https://app.infisical.com - - # With custom domain (EU Cloud) + # EU Cloud (Custom domain) infisical login --email user@example.com --password "your-password" --domain https://eu.infisical.com # Output only JWT token for scripting @@ -523,7 +520,6 @@ The following examples demonstrate different ways to authenticate as a user with # Set credentials as environment variables export INFISICAL_EMAIL="user@example.com" export INFISICAL_PASSWORD="your-password" - export INFISICAL_API_URL="https://app.infisical.com/api" # Login without additional flags infisical login From 5699b7dfd02892f00de4167a3b97171bbf46af3b Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 23 Oct 2025 12:27:03 +0400 Subject: [PATCH 079/146] fix: remove mentions of oidc-jwt --- docs/cli/commands/login.mdx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/cli/commands/login.mdx b/docs/cli/commands/login.mdx index 4eeae76e0..1f7a08350 100644 --- a/docs/cli/commands/login.mdx +++ b/docs/cli/commands/login.mdx @@ -308,7 +308,7 @@ Machine identity authentication methods are designed for automated systems, serv Run the `login` command with the following flags to obtain an access token: ```bash - infisical login --method=jwt-auth --jwt= --machine-identity-id= + infisical login --method=jwt-auth --jwt= --machine-identity-id= ``` @@ -333,7 +333,8 @@ The login command supports a number of flags that you can use for different auth - `gcp-id-token`: Login using a GCP ID token native auth. - `gcp-iam`: Login using a GCP IAM. - `aws-iam`: Login using an AWS IAM native auth. - - `oidc-auth`: Login using oidc auth. + - `oidc-auth`: Login using OIDC auth. + - `jwt-auth`: Login using a plain JWT token. @@ -466,16 +467,16 @@ The login command supports a number of flags that you can use for different auth - + ```bash - infisical login --oidc-jwt= + infisical login --jwt= --machine-identity-id= ``` #### Description - The JWT provided by an identity provider for OIDC authentication. + The JWT provided by an identity provider for OIDC or plain JWT authentication. This is required if the `--method` flag is set to `oidc-auth` or `jwt-auth`. - The `oidc-jwt` flag can be substituted with the `INFISICAL_OIDC_AUTH_JWT` environment variable. + The `jwt` flag can be substituted with the `INFISICAL_JWT` environment variable. From 49ec838f357bfdb6cf65d17be080ebcb6ded6afa Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 23 Oct 2025 15:04:31 +0400 Subject: [PATCH 080/146] fix(aws-auth): better error logging --- .../identity-aws-auth/identity-aws-auth-service.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts index 1814afb2e..3aadc6b4a 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts @@ -21,6 +21,7 @@ import { UnauthorizedError } from "@app/lib/errors"; import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip"; +import { logger } from "@app/lib/logger"; import { ActorType, AuthTokenType } from "../auth/auth-type"; import { TIdentityDALFactory } from "../identity/identity-dal"; @@ -147,6 +148,8 @@ export const identityAwsAuthServiceFactory = ({ if (identityAwsAuth.allowedPrincipalArns) { // validate if Arn is in the list of allowed Principal ARNs + const formattedArn = extractPrincipalArn(Arn); + const isArnAllowed = identityAwsAuth.allowedPrincipalArns .split(",") .map((principalArn) => principalArn.trim()) @@ -155,13 +158,16 @@ export const identityAwsAuthServiceFactory = ({ // considers exact matches + wildcard matches // heavily validated in router const regex = new RE2(`^${principalArn.replaceAll("*", ".*")}$`); - return regex.test(extractPrincipalArn(Arn)); + return regex.test(formattedArn); }); - if (!isArnAllowed) + if (!isArnAllowed) { + logger.info({ formattedArn, rawArn: Arn }, "Access denied: AWS principal ARN not allowed"); + throw new UnauthorizedError({ - message: "Access denied: AWS principal ARN not allowed." + message: `Access denied: AWS principal ARN not allowed. [principal-arn=${formattedArn}]` }); + } } const identityAccessToken = await identityAwsAuthDAL.transaction(async (tx) => { From 02ba35a51eb90868cc29a9e13b72f054f6870f7a Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Thu, 23 Oct 2025 15:10:15 +0400 Subject: [PATCH 081/146] Update identity-aws-auth-service.ts --- .../services/identity-aws-auth/identity-aws-auth-service.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts index 3aadc6b4a..3bbe88824 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts @@ -162,7 +162,9 @@ export const identityAwsAuthServiceFactory = ({ }); if (!isArnAllowed) { - logger.info({ formattedArn, rawArn: Arn }, "Access denied: AWS principal ARN not allowed"); + logger.error( + `AWS Auth Login: AWS principal ARN not allowed [principal-arn=${formattedArn}] [raw-arn=${Arn}] [identity-id=${identity.id}]` + ); throw new UnauthorizedError({ message: `Access denied: AWS principal ARN not allowed. [principal-arn=${formattedArn}]` From e364eb15dbdb81f0ed5d50417a6bf66a8c36ae50 Mon Sep 17 00:00:00 2001 From: Carlos Monastyrski Date: Thu, 23 Oct 2025 10:23:40 -0300 Subject: [PATCH 082/146] Address greptile comments --- ...1021112356_add-certificate-auto-renewal.ts | 6 +- backend/src/server/routes/index.ts | 3 - .../server/routes/v3/certificates-router.ts | 12 +- .../certificate-constants.ts | 30 ++ .../certificate-common/certificate-utils.ts | 75 +++++ .../certificate-v3/certificate-v3-queue.ts | 266 ++++++------------ .../certificate-v3-service.test.ts | 4 +- .../certificate-v3/certificate-v3-service.ts | 5 +- .../services/certificate/certificate-dal.ts | 45 ++- .../src/hooks/api/certificates/mutations.tsx | 2 +- frontend/src/hooks/api/certificates/types.ts | 1 + .../CertificateManageRenewalModal.tsx | 225 +++++++-------- .../CertificateRenewalConfigModal.tsx | 35 +-- .../components/CertificatesTable.tsx | 45 +-- 14 files changed, 396 insertions(+), 358 deletions(-) diff --git a/backend/src/db/migrations/20251021112356_add-certificate-auto-renewal.ts b/backend/src/db/migrations/20251021112356_add-certificate-auto-renewal.ts index e60e8458f..2226194e5 100644 --- a/backend/src/db/migrations/20251021112356_add-certificate-auto-renewal.ts +++ b/backend/src/db/migrations/20251021112356_add-certificate-auto-renewal.ts @@ -5,8 +5,7 @@ import { TableName } from "../schemas"; export async function up(knex: Knex): Promise { if (await knex.schema.hasColumn(TableName.PkiApiEnrollmentConfig, "autoRenewDays")) { await knex.schema.alterTable(TableName.PkiApiEnrollmentConfig, (t) => { - t.dropColumn("autoRenewDays"); - t.integer("renewBeforeDays"); + t.renameColumn("autoRenewDays", "renewBeforeDays"); }); } @@ -46,8 +45,7 @@ export async function down(knex: Knex): Promise { if (await knex.schema.hasColumn(TableName.PkiApiEnrollmentConfig, "renewBeforeDays")) { await knex.schema.alterTable(TableName.PkiApiEnrollmentConfig, (t) => { - t.dropColumn("renewBeforeDays"); - t.integer("autoRenewDays"); + t.renameColumn("renewBeforeDays", "autoRenewDays"); }); } } diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index 5df10e5e0..d7a84e87f 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -2147,9 +2147,6 @@ export const registerRoutes = async ( const certificateV3Queue = certificateV3QueueServiceFactory({ queueService, certificateDAL, - certificateAuthorityDAL, - certificateProfileDAL, - projectDAL, certificateV3Service, auditLogService }); diff --git a/backend/src/server/routes/v3/certificates-router.ts b/backend/src/server/routes/v3/certificates-router.ts index f4a94321c..126a3b146 100644 --- a/backend/src/server/routes/v3/certificates-router.ts +++ b/backend/src/server/routes/v3/certificates-router.ts @@ -406,10 +406,14 @@ export const registerCertificatesRouter = async (server: FastifyZodProvider) => params: z.object({ certificateId: z.string().uuid() }), - body: z.object({ - renewBeforeDays: z.number().int().min(1).max(30).optional(), - disableAutoRenewal: z.boolean().optional() - }), + body: z + .object({ + renewBeforeDays: z.number().int().min(1).max(30).optional(), + disableAutoRenewal: z.boolean().optional() + }) + .refine((data) => !(data.renewBeforeDays !== undefined && data.disableAutoRenewal === true), { + message: "Cannot specify both renewBeforeDays and disableAutoRenewal" + }), response: { 200: z.object({ message: z.string(), diff --git a/backend/src/services/certificate-common/certificate-constants.ts b/backend/src/services/certificate-common/certificate-constants.ts index 6500b0fab..a7dea2c96 100644 --- a/backend/src/services/certificate-common/certificate-constants.ts +++ b/backend/src/services/certificate-common/certificate-constants.ts @@ -175,6 +175,36 @@ export enum CertSignatureAlgorithm { ECDSA_SHA512 = "ECDSA-SHA512" } +export enum CertificateRenewalErrorType { + TEMPLATE_VALIDATION_FAILED = "TEMPLATE_VALIDATION_FAILED", + CA_NOT_FOUND = "CA_NOT_FOUND", + CA_INACTIVE = "CA_INACTIVE", + CERTIFICATE_OUTLIVES_CA = "CERTIFICATE_OUTLIVES_CA", + TTL_TOO_SHORT = "TTL_TOO_SHORT", + NOT_ELIGIBLE = "NOT_ELIGIBLE", + VALIDITY_EXCEEDS_MAXIMUM = "VALIDITY_EXCEEDS_MAXIMUM", + NOT_ALLOWED_BY_TEMPLATE = "NOT_ALLOWED_BY_TEMPLATE", + UNKNOWN_ERROR = "UNKNOWN_ERROR" +} + +export const CERTIFICATE_RENEWAL_ERROR_MESSAGES = { + [CertificateRenewalErrorType.TEMPLATE_VALIDATION_FAILED]: + "Auto-renewal failed: certificate template policy has changed and this certificate no longer meets the requirements", + [CertificateRenewalErrorType.CA_NOT_FOUND]: + "Auto-renewal failed: Certificate Authority for this certificate is no longer available", + [CertificateRenewalErrorType.CA_INACTIVE]: "Auto-renewal failed: Certificate Authority is currently inactive", + [CertificateRenewalErrorType.CERTIFICATE_OUTLIVES_CA]: + "Auto-renewal failed: certificate would outlive the Certificate Authority", + [CertificateRenewalErrorType.TTL_TOO_SHORT]: + "Auto-renewal failed: certificate validity period is too short for the renewal threshold", + [CertificateRenewalErrorType.NOT_ELIGIBLE]: "Auto-renewal failed: certificate is not eligible for automatic renewal", + [CertificateRenewalErrorType.VALIDITY_EXCEEDS_MAXIMUM]: + "Auto-renewal failed: certificate validity period exceeds the maximum allowed by the profile template", + [CertificateRenewalErrorType.NOT_ALLOWED_BY_TEMPLATE]: + "Auto-renewal failed: certificate settings are no longer allowed by the profile template", + [CertificateRenewalErrorType.UNKNOWN_ERROR]: "Auto-renewal failed: an unexpected error occurred" +} as const; + export const CERTIFICATE_RENEWAL_CONFIG = { MIN_RENEW_BEFORE_DAYS: 1, MAX_RENEW_BEFORE_DAYS: 30, diff --git a/backend/src/services/certificate-common/certificate-utils.ts b/backend/src/services/certificate-common/certificate-utils.ts index b88f183db..3e1b7b5b4 100644 --- a/backend/src/services/certificate-common/certificate-utils.ts +++ b/backend/src/services/certificate-common/certificate-utils.ts @@ -1,8 +1,12 @@ import RE2 from "re2"; +import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors"; + import { CertExtendedKeyUsage, CertKeyUsage } from "../certificate/certificate-types"; import { CertExtendedKeyUsageType, + CERTIFICATE_RENEWAL_ERROR_MESSAGES, + CertificateRenewalErrorType, CertKeyUsageType, mapExtendedKeyUsageToLegacy, mapKeyUsageToLegacy, @@ -196,3 +200,74 @@ export const convertExtendedKeyUsageArrayToLegacy = ( ): CertExtendedKeyUsage[] | undefined => { return usages?.map(convertToLegacyExtendedKeyUsage); }; + +export const categorizeCertificateRenewalError = (error: unknown): string => { + if (!error) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.UNKNOWN_ERROR]; + } + + const errorMessage = error instanceof Error ? error.message : String(error); + + if (error instanceof NotFoundError) { + if (errorMessage.includes("Certificate Authority")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.CA_NOT_FOUND]; + } + if (errorMessage.includes("Certificate template")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.TEMPLATE_VALIDATION_FAILED]; + } + } + + if (error instanceof BadRequestError) { + if (errorMessage.includes("Certificate Authority is") && errorMessage.includes("must be ACTIVE")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.CA_INACTIVE]; + } + if (errorMessage.includes("would expire") && errorMessage.includes("after its issuing CA")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.CERTIFICATE_OUTLIVES_CA]; + } + if (errorMessage.includes("TTL") && errorMessage.includes("must be greater than renewal threshold")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.TTL_TOO_SHORT]; + } + if (errorMessage.includes("not eligible for renewal")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.NOT_ELIGIBLE]; + } + if (errorMessage.includes("Requested validity period exceeds maximum allowed duration")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.VALIDITY_EXCEEDS_MAXIMUM]; + } + if (errorMessage.includes("not allowed by template policy")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.NOT_ALLOWED_BY_TEMPLATE]; + } + } + + if (error instanceof ForbiddenRequestError) { + if (errorMessage.includes("Template validation failed")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.TEMPLATE_VALIDATION_FAILED]; + } + } + + if (errorMessage.includes("Template validation failed")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.TEMPLATE_VALIDATION_FAILED]; + } + if (errorMessage.includes("Certificate Authority") && errorMessage.includes("not found")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.CA_NOT_FOUND]; + } + if (errorMessage.includes("Certificate Authority is") && errorMessage.includes("must be ACTIVE")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.CA_INACTIVE]; + } + if (errorMessage.includes("would expire") && errorMessage.includes("after its issuing CA")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.CERTIFICATE_OUTLIVES_CA]; + } + if (errorMessage.includes("TTL") && errorMessage.includes("must be greater than renewal threshold")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.TTL_TOO_SHORT]; + } + if (errorMessage.includes("not eligible for renewal")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.NOT_ELIGIBLE]; + } + if (errorMessage.includes("Requested validity period exceeds maximum allowed duration")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.VALIDITY_EXCEEDS_MAXIMUM]; + } + if (errorMessage.includes("not allowed by template policy")) { + return CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.NOT_ALLOWED_BY_TEMPLATE]; + } + + return `${CERTIFICATE_RENEWAL_ERROR_MESSAGES[CertificateRenewalErrorType.UNKNOWN_ERROR]}: ${errorMessage}`; +}; diff --git a/backend/src/services/certificate-v3/certificate-v3-queue.ts b/backend/src/services/certificate-v3/certificate-v3-queue.ts index f756f4e26..afb69f67f 100644 --- a/backend/src/services/certificate-v3/certificate-v3-queue.ts +++ b/backend/src/services/certificate-v3/certificate-v3-queue.ts @@ -5,19 +5,13 @@ import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue"; import { ActorType } from "../auth/auth-type"; import { TCertificateDALFactory } from "../certificate/certificate-dal"; -import { CertStatus } from "../certificate/certificate-types"; -import { TCertificateAuthorityDALFactory } from "../certificate-authority/certificate-authority-dal"; import { CERTIFICATE_RENEWAL_CONFIG } from "../certificate-common/certificate-constants"; -import { TCertificateProfileDALFactory } from "../certificate-profile/certificate-profile-dal"; -import { TProjectDALFactory } from "../project/project-dal"; +import { categorizeCertificateRenewalError } from "../certificate-common/certificate-utils"; import { TCertificateV3ServiceFactory } from "./certificate-v3-service"; type TCertificateV3QueueServiceFactoryDep = { queueService: TQueueServiceFactory; - certificateDAL: TCertificateDALFactory; - certificateAuthorityDAL: Pick; - certificateProfileDAL: Pick; - projectDAL: Pick; + certificateDAL: Pick; certificateV3Service: TCertificateV3ServiceFactory; auditLogService: Pick; }; @@ -25,9 +19,6 @@ type TCertificateV3QueueServiceFactoryDep = { export const certificateV3QueueServiceFactory = ({ queueService, certificateDAL, - certificateAuthorityDAL, - certificateProfileDAL, - projectDAL, certificateV3Service, auditLogService }: TCertificateV3QueueServiceFactoryDep) => { @@ -38,190 +29,109 @@ export const certificateV3QueueServiceFactory = ({ const { QUEUE_BATCH_SIZE } = CERTIFICATE_RENEWAL_CONFIG; let offset = 0; let hasMore = true; + let totalCertificatesFound = 0; + let totalCertificatesRenewed = 0; while (hasMore) { - const certificates = await certificateDAL.find( - { - $notNull: ["profileId"], - status: CertStatus.ACTIVE, - renewedById: null, - renewalError: null, - revokedAt: null - }, - { - limit: QUEUE_BATCH_SIZE, - offset - } - ); + const certificates = await certificateDAL.findCertificatesEligibleForRenewal({ + limit: QUEUE_BATCH_SIZE, + offset + }); if (certificates.length === 0) { hasMore = false; break; } - await Promise.all( - certificates.map(async (certificate) => { - try { - if (!certificate.profileId || !certificate.notAfter) { - return; - } - - const profile = await certificateProfileDAL.findByIdWithConfigs(certificate.profileId); - if (!profile) { - logger.warn(`Profile not found for certificate ${certificate.id}`); - return; - } - - const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(profile.caId); - if (!ca) { - logger.warn(`CA not found for certificate ${certificate.id}`); - return; - } - - const profileAutoRenewEnabled = profile.apiConfig?.autoRenew === true; - const certificateHasRenewalConfig = - certificate.renewBeforeDays != null && certificate.renewBeforeDays > 0; - - if (!profileAutoRenewEnabled && !certificateHasRenewalConfig) { - return; - } - - const now = new Date(); - if (certificate.notAfter <= now) { - return; - } - - const renewBeforeDays = certificate.renewBeforeDays || profile.apiConfig?.renewBeforeDays; - if (!renewBeforeDays) { - return; - } + totalCertificatesFound += certificates.length; + logger.info( + `${QueueJobs.CertificateV3DailyAutoRenewal}: found ${certificates.length} certificates eligible for renewal (batch ${Math.floor(offset / QUEUE_BATCH_SIZE) + 1}, total found so far: ${totalCertificatesFound})` + ); + for (const certificate of certificates) { + try { + if (certificate.renewBeforeDays) { const { MIN_RENEW_BEFORE_DAYS, MAX_RENEW_BEFORE_DAYS } = CERTIFICATE_RENEWAL_CONFIG; - if (renewBeforeDays < MIN_RENEW_BEFORE_DAYS || renewBeforeDays > MAX_RENEW_BEFORE_DAYS) { - logger.warn(`Invalid renewal threshold ${renewBeforeDays} for certificate ${certificate.id}`); - return; - } - - const expiryDate = new Date(certificate.notAfter); - const renewalDate = new Date(expiryDate.getTime() - renewBeforeDays * 24 * 60 * 60 * 1000); - - const shouldRenew = renewalDate <= now; - - if (shouldRenew) { - logger.info(`Auto-renewing certificate ${certificate.id} (common name: ${certificate.commonName})`); - - const project = await projectDAL.findById(certificate.projectId); - if (!project) { - logger.error(`Project not found for certificate ${certificate.id}`); - return; - } - - await certificateV3Service.renewCertificate({ - actor: ActorType.PLATFORM, - actorId: "", - actorAuthMethod: null, - actorOrgId: project.orgId, - certificateId: certificate.id, - internal: true - }); - - await certificateDAL.updateById(certificate.id, { - renewalError: null - }); - - await auditLogService.createAuditLog({ - projectId: certificate.projectId, - actor: { - type: ActorType.PLATFORM, - metadata: {} - }, - event: { - type: EventType.AUTOMATED_RENEW_CERTIFICATE, - metadata: { - certificateId: certificate.id, - commonName: certificate.commonName || "", - profileId: certificate.profileId, - renewBeforeDays: certificate.renewBeforeDays?.toString() || "" - } - } - }); - - logger.info(`Successfully auto-renewed certificate ${certificate.id}`); - } - } catch (error) { - logger.error( - error, - `Failed to auto-renew certificate ${certificate.id} (common name: ${certificate.commonName})` - ); - - const errorMessage = error instanceof Error ? error.message : "Unknown error"; - let categorizedError = errorMessage; - - if (errorMessage.includes("Template validation failed")) { - categorizedError = - "Auto-renewal failed: certificate template policy has changed and this certificate no longer meets the requirements"; - } else if (errorMessage.includes("Certificate Authority") && errorMessage.includes("not found")) { - categorizedError = - "Auto-renewal failed: Certificate Authority for this certificate is no longer available"; - } else if (errorMessage.includes("Certificate Authority is") && errorMessage.includes("must be ACTIVE")) { - categorizedError = "Auto-renewal failed: Certificate Authority is currently inactive"; - } else if (errorMessage.includes("would expire") && errorMessage.includes("after its issuing CA")) { - categorizedError = "Auto-renewal failed: certificate would outlive the Certificate Authority"; - } else if ( - errorMessage.includes("TTL") && - errorMessage.includes("must be greater than renewal threshold") + if ( + certificate.renewBeforeDays < MIN_RENEW_BEFORE_DAYS || + certificate.renewBeforeDays > MAX_RENEW_BEFORE_DAYS ) { - categorizedError = - "Auto-renewal failed: certificate validity period is too short for the renewal threshold"; - } else if (errorMessage.includes("not eligible for renewal")) { - categorizedError = "Auto-renewal failed: certificate is not eligible for automatic renewal"; - } else if (errorMessage.includes("Requested validity period exceeds maximum allowed duration")) { - categorizedError = - "Auto-renewal failed: certificate validity period exceeds the maximum allowed by the profile template"; - } else if (errorMessage.includes("not allowed by template policy")) { - categorizedError = - "Auto-renewal failed: certificate settings are no longer allowed by the profile template"; - } else { - categorizedError = `Auto-renewal failed: ${errorMessage}`; - } - - try { - await certificateDAL.updateById(certificate.id, { - renewalError: categorizedError - }); - } catch (updateError) { - logger.error(updateError, `Failed to update renewal error for certificate ${certificate.id}`); - } - - try { - await auditLogService.createAuditLog({ - projectId: certificate.projectId, - actor: { - type: ActorType.PLATFORM, - metadata: {} - }, - event: { - type: EventType.AUTOMATED_RENEW_CERTIFICATE_FAILED, - metadata: { - certificateId: certificate.id, - commonName: certificate.commonName || "", - profileId: certificate.profileId || "", - renewBeforeDays: certificate.renewBeforeDays?.toString() || "", - error: categorizedError - } - } - }); - } catch (auditError) { - logger.error(auditError, `Failed to create audit log for failed certificate renewal ${certificate.id}`); + // eslint-disable-next-line no-continue + continue; } } - }) - ); + + await certificateV3Service.renewCertificate({ + actor: ActorType.PLATFORM, + actorId: "", + actorAuthMethod: null, + actorOrgId: "", + certificateId: certificate.id, + internal: true + }); + + await certificateDAL.updateById(certificate.id, { + renewalError: null + }); + totalCertificatesRenewed += 1; + + await auditLogService.createAuditLog({ + projectId: certificate.projectId, + actor: { + type: ActorType.PLATFORM, + metadata: {} + }, + event: { + type: EventType.AUTOMATED_RENEW_CERTIFICATE, + metadata: { + certificateId: certificate.id, + commonName: certificate.commonName || "", + profileId: certificate.profileId!, + renewBeforeDays: certificate.renewBeforeDays?.toString() || "" + } + } + }); + } catch (error) { + const categorizedError: string = categorizeCertificateRenewalError(error); + + try { + await certificateDAL.updateById(certificate.id, { + renewalError: categorizedError + }); + } catch (updateError) { + logger.error(updateError, `Failed to update renewal error for certificate ${certificate.id}`); + } + + try { + await auditLogService.createAuditLog({ + projectId: certificate.projectId, + actor: { + type: ActorType.PLATFORM, + metadata: {} + }, + event: { + type: EventType.AUTOMATED_RENEW_CERTIFICATE_FAILED, + metadata: { + certificateId: certificate.id, + commonName: certificate.commonName || "", + profileId: certificate.profileId || "", + renewBeforeDays: certificate.renewBeforeDays?.toString() || "", + error: categorizedError + } + } + }); + } catch (auditError) { + logger.error(auditError, `Failed to create audit log for failed certificate renewal ${certificate.id}`); + } + } + } offset += QUEUE_BATCH_SIZE; } - logger.info(`${QueueJobs.CertificateV3DailyAutoRenewal}: queue task completed`); + logger.info( + `${QueueJobs.CertificateV3DailyAutoRenewal}: queue task completed. Renewed ${totalCertificatesRenewed} certificates out of ${totalCertificatesFound}` + ); } }); diff --git a/backend/src/services/certificate-v3/certificate-v3-service.test.ts b/backend/src/services/certificate-v3/certificate-v3-service.test.ts index a4f0f0818..2e7c87fb6 100644 --- a/backend/src/services/certificate-v3/certificate-v3-service.test.ts +++ b/backend/src/services/certificate-v3/certificate-v3-service.test.ts @@ -1646,7 +1646,7 @@ describe("CertificateV3Service", () => { ...mockActor }) ).rejects.toThrow( - "Certificate renewal failed because requested validity period exceeds maximum allowed duration by the profile template" + "Certificate renewal failed because requested validity period exceeds maximum allowed duration by the profile template: Subject alternative name not allowed" ); // Should store template validation error @@ -1788,7 +1788,7 @@ describe("CertificateV3Service", () => { certificateId: "cert-123", ...mockActor }) - ).rejects.toThrow("New certificate would expire"); + ).rejects.toThrow(/New certificate would expire \(.+\) after its issuing CA \(.+\)/); }); it("should allow manual renewal outside window (manual renewal always bypasses window)", async () => { diff --git a/backend/src/services/certificate-v3/certificate-v3-service.ts b/backend/src/services/certificate-v3/certificate-v3-service.ts index c987fb77b..7b933b68f 100644 --- a/backend/src/services/certificate-v3/certificate-v3-service.ts +++ b/backend/src/services/certificate-v3/certificate-v3-service.ts @@ -733,8 +733,9 @@ export const certificateV3ServiceFactory = ({ ? originalCert.altNames.split(",").map((san) => { const trimmed = san.trim(); const isIp = - new RE2("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$").test(trimmed) || - new RE2("^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$").test(trimmed); + trimmed.length <= 45 && + (new RE2("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$").test(trimmed) || + new RE2("^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$").test(trimmed)); return { type: isIp ? CertSubjectAlternativeNameType.IP_ADDRESS : CertSubjectAlternativeNameType.DNS_NAME, value: trimmed diff --git a/backend/src/services/certificate/certificate-dal.ts b/backend/src/services/certificate/certificate-dal.ts index 88808bd63..99a5885b1 100644 --- a/backend/src/services/certificate/certificate-dal.ts +++ b/backend/src/services/certificate/certificate-dal.ts @@ -114,12 +114,55 @@ export const certificateDALFactory = (db: TDbClient) => { } }; + const findCertificatesEligibleForRenewal = async ({ + limit, + offset + }: { + limit: number; + offset: number; + }): Promise => { + try { + const now = new Date(); + const endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 999); + + const certs = (await db + .replicaNode()(TableName.Certificate) + .select(`${TableName.Certificate}.*`) + .where(`${TableName.Certificate}.status`, CertStatus.ACTIVE) + .whereNull(`${TableName.Certificate}.renewedById`) + .whereNull(`${TableName.Certificate}.renewalError`) + .whereNull(`${TableName.Certificate}.revokedAt`) + .whereNotNull(`${TableName.Certificate}.profileId`) + .whereNotNull(`${TableName.Certificate}.notAfter`) + .where(`${TableName.Certificate}.notAfter`, ">", now) + .where((queryBuilder) => { + void queryBuilder.where((subQuery) => { + void subQuery + .whereNotNull(`${TableName.Certificate}.renewBeforeDays`) + .where(`${TableName.Certificate}.renewBeforeDays`, ">", 0) + .whereRaw( + `"${TableName.Certificate}"."notAfter" - INTERVAL '1 day' * "${TableName.Certificate}"."renewBeforeDays" <= ?`, + [endOfDay] + ); + }); + }) + .limit(limit) + .offset(offset) + .orderBy(`${TableName.Certificate}.notAfter`, "asc")) as TCertificates[]; + + return certs; + } catch (error) { + throw new DatabaseError({ error, name: "Find certificates eligible for renewal" }); + } + }; + return { ...certificateOrm, countCertificatesInProject, countCertificatesForPkiSubscriber, findLatestActiveCertForSubscriber, findAllActiveCertsForSubscriber, - findExpiredSyncedCertificates + findExpiredSyncedCertificates, + findCertificatesEligibleForRenewal }; }; diff --git a/frontend/src/hooks/api/certificates/mutations.tsx b/frontend/src/hooks/api/certificates/mutations.tsx index 699cbb8eb..75a2ca10a 100644 --- a/frontend/src/hooks/api/certificates/mutations.tsx +++ b/frontend/src/hooks/api/certificates/mutations.tsx @@ -115,7 +115,7 @@ export const useUpdateRenewalConfig = () => { return useMutation< { message: string; renewBeforeDays?: number }, object, - TUpdateRenewalConfigDTO & { disableAutoRenewal?: boolean } + TUpdateRenewalConfigDTO >({ mutationFn: async ({ certificateId, renewBeforeDays, disableAutoRenewal }) => { const { data } = await apiRequest.patch<{ message: string; renewBeforeDays?: number }>( diff --git a/frontend/src/hooks/api/certificates/types.ts b/frontend/src/hooks/api/certificates/types.ts index 80d02e3f8..73505b344 100644 --- a/frontend/src/hooks/api/certificates/types.ts +++ b/frontend/src/hooks/api/certificates/types.ts @@ -67,5 +67,6 @@ export type TRenewCertificateResponse = { export type TUpdateRenewalConfigDTO = { certificateId: string; renewBeforeDays?: number; + disableAutoRenewal?: boolean; projectSlug: string; }; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateManageRenewalModal.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateManageRenewalModal.tsx index 86adf948e..dd3ecb9b9 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateManageRenewalModal.tsx +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateManageRenewalModal.tsx @@ -13,24 +13,91 @@ const DEFAULT_RENEWAL_BEFORE_DAYS = 20; const MIN_RENEWAL_BEFORE_DAYS = 1; const MAX_RENEWAL_BEFORE_DAYS = 30; -const formSchema = z - .object({ +const createFormSchema = (ttlDays: number, notAfter: string) => + z.object({ renewBeforeDays: z .number() .min(MIN_RENEWAL_BEFORE_DAYS, `Renewal days must be at least ${MIN_RENEWAL_BEFORE_DAYS}`) .max(MAX_RENEWAL_BEFORE_DAYS, `Renewal days cannot exceed ${MAX_RENEWAL_BEFORE_DAYS}`) - }) - .refine(() => { - return true; - }, "Invalid renewal configuration"); + .refine( + (value) => value < ttlDays, + (value) => ({ + message: `Renewal days (${value}) must be less than certificate TTL (${ttlDays} days)` + }) + ) + .refine( + (value) => { + const expiryDate = new Date(notAfter); + const renewalDate = new Date(expiryDate.getTime() - value * 24 * 60 * 60 * 1000); + const tomorrow = new Date(); + tomorrow.setDate(tomorrow.getDate() + 1); + tomorrow.setHours(0, 0, 0, 0); + return renewalDate >= tomorrow; + }, + () => ({ + message: "Renewals can only be scheduled from tomorrow onwards." + }) + ) + }); -type FormData = z.infer; +type FormData = z.infer>; type Props = { popUp: UsePopUpState<["manageRenewal"]>; handlePopUpToggle: (popUpName: keyof UsePopUpState<["manageRenewal"]>, state?: boolean) => void; }; +const RenewalConfigForm = ({ + control, + errors, + onSubmit, + isLoading, + buttonText, + onCancel +}: { + control: any; + errors: { renewBeforeDays?: { message?: string } }; + onSubmit: (e?: React.BaseSyntheticEvent) => Promise; + isLoading: boolean; + buttonText: string; + onCancel: () => void; +}) => ( +
+ + ( + { + const value = parseInt(e.target.value, 10); + field.onChange(value); + }} + placeholder="Enter days before expiration" + /> + )} + /> + + +
+ + +
+
+); + export const CertificateManageRenewalModal = ({ popUp, handlePopUpToggle }: Props) => { const { currentProject } = useProject(); const { mutateAsync: updateRenewalConfig, isPending: isUpdatingConfig } = @@ -41,7 +108,7 @@ export const CertificateManageRenewalModal = ({ popUp, handlePopUpToggle }: Prop commonName: string; profileId: string; renewBeforeDays?: number; - ttlDays: number; + ttlDays?: number; notAfter: string; renewalError?: string; renewedFromId?: string; @@ -54,6 +121,11 @@ export const CertificateManageRenewalModal = ({ popUp, handlePopUpToggle }: Prop const hasRenewalError = Boolean(certificateData?.renewalError); + const formSchema = createFormSchema( + certificateData?.ttlDays || 365, + certificateData?.notAfter || "" + ); + const { control, handleSubmit, @@ -84,30 +156,6 @@ export const CertificateManageRenewalModal = ({ popUp, handlePopUpToggle }: Prop return; } - if (data.renewBeforeDays >= certificateData.ttlDays) { - createNotification({ - text: `Renewal days (${data.renewBeforeDays}) must be less than certificate TTL (${certificateData.ttlDays} days)`, - type: "error" - }); - return; - } - - const expiryDate = new Date(certificateData.notAfter); - const renewalDate = new Date( - expiryDate.getTime() - data.renewBeforeDays * 24 * 60 * 60 * 1000 - ); - const tomorrow = new Date(); - tomorrow.setDate(tomorrow.getDate() + 1); - tomorrow.setHours(0, 0, 0, 0); - - if (renewalDate < tomorrow) { - createNotification({ - text: "The renewal date cannot be set to today or any past date. Renewals can only be scheduled from tomorrow onwards.", - type: "error" - }); - return; - } - await updateRenewalConfig({ certificateId: certificateData.certificateId, renewBeforeDays: data.renewBeforeDays, @@ -133,8 +181,6 @@ export const CertificateManageRenewalModal = ({ popUp, handlePopUpToggle }: Prop } }; - const isLoading = isUpdatingConfig; - const getModalTitle = () => { if (hasRenewalError) { return `Fix Auto-Renewal: ${certificateData?.commonName || ""}`; @@ -145,6 +191,10 @@ export const CertificateManageRenewalModal = ({ popUp, handlePopUpToggle }: Prop return `Enable Auto-Renewal for ${certificateData?.commonName || ""}`; }; + if (!certificateData) { + return null; + } + return ( - {/* Show renewal error if present */} {hasRenewalError && (
@@ -173,100 +222,26 @@ export const CertificateManageRenewalModal = ({ popUp, handlePopUpToggle }: Prop
)} - {/* Configuration form - shown for all cases except when enabled and no error */} {(!isAutoRenewalEnabled || hasRenewalError) && ( -
- - ( - { - const value = parseInt(e.target.value, 10); - field.onChange(value); - }} - placeholder="Enter days before expiration" - /> - )} - /> - - -
- - -
-
+ handlePopUpToggle("manageRenewal", false)} + /> )} - {/* Show edit form for enabled auto-renewal without errors */} {isAutoRenewalEnabled && !hasRenewalError && ( -
- - ( - { - const value = parseInt(e.target.value, 10); - field.onChange(value); - }} - placeholder="Enter days before expiration" - /> - )} - /> - - -
- - -
-
+ handlePopUpToggle("manageRenewal", false)} + /> )} diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRenewalConfigModal.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRenewalConfigModal.tsx index 1c195dd22..c952f1e54 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRenewalConfigModal.tsx +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRenewalConfigModal.tsx @@ -8,14 +8,21 @@ import { useProject } from "@app/context"; import { useUpdateRenewalConfig } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; -const formSchema = z.object({ - renewBeforeDays: z - .number() - .min(1, "Renewal days must be at least 1") - .max(365, "Renewal days cannot exceed 365") -}); +const createFormSchema = (ttlDays: number) => + z.object({ + renewBeforeDays: z + .number() + .min(1, "Renewal days must be at least 1") + .max(365, "Renewal days cannot exceed 365") + .refine( + (value) => value < ttlDays, + (value) => ({ + message: `Renewal days (${value}) must be less than certificate TTL (${ttlDays} days)` + }) + ) + }); -type FormData = z.infer; +type FormData = z.infer>; type Props = { popUp: UsePopUpState<["configureRenewal"]>; @@ -37,6 +44,8 @@ export const CertificateRenewalConfigModal = ({ popUp, handlePopUpToggle }: Prop ttlDays: number; }; + const formSchema = createFormSchema(certificateData.ttlDays); + const { control, handleSubmit, @@ -45,7 +54,7 @@ export const CertificateRenewalConfigModal = ({ popUp, handlePopUpToggle }: Prop } = useForm({ resolver: zodResolver(formSchema), defaultValues: { - renewBeforeDays: certificateData?.renewBeforeDays || 7 + renewBeforeDays: certificateData?.renewBeforeDays || 1 } }); @@ -53,14 +62,6 @@ export const CertificateRenewalConfigModal = ({ popUp, handlePopUpToggle }: Prop const onSubmit = async (data: FormData) => { try { - if (data.renewBeforeDays >= certificateData.ttlDays) { - createNotification({ - text: `Renewal days (${data.renewBeforeDays}) must be less than certificate TTL (${certificateData.ttlDays} days)`, - type: "error" - }); - return; - } - if (!currentProject?.slug) { createNotification({ text: "Project not found", @@ -144,7 +145,7 @@ export const CertificateRenewalConfigModal = ({ popUp, handlePopUpToggle }: Prop {renewBeforeDays && certificateData?.ttlDays && (

- {renewBeforeDays >= (certificateData.ttlDays || 0) + {renewBeforeDays >= certificateData.ttlDays ? "⚠️ Renewal days must be less than certificate TTL" : `✓ Certificate will be renewed ${renewBeforeDays} days before expiration`}

diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.tsx index 4ccc662d6..72c047bec 100644 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.tsx +++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.tsx @@ -91,10 +91,14 @@ const getAutoRenewalInfo = (certificate: TCertificate) => { return { text: "Due Now", variant: "danger" as const }; } - const daysUntilRenewal = Math.ceil( + const daysUntilRenewal = Math.floor( (renewalDate.getTime() - now.getTime()) / (24 * 60 * 60 * 1000) ); + if (daysUntilRenewal === 0) { + return { text: "Renews today", variant: "primary" as const }; + } + if (daysUntilRenewal <= 7) { return { text: `Renews in ${daysUntilRenewal}d`, variant: "primary" as const }; } @@ -204,6 +208,14 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => { data?.certificates.map((certificate) => { const { variant, label } = getCertValidUntilBadgeDetails(certificate.notAfter); const autoRenewalInfo = getAutoRenewalInfo(certificate); + + const isRevoked = certificate.status === CertStatus.REVOKED; + const isExpired = new Date(certificate.notAfter) < new Date(); + const isExpiringWithinDay = isExpiringWithinOneDay(certificate.notAfter); + const hasFailed = Boolean(certificate.renewalError); + const isAutoRenewalEnabled = Boolean( + certificate.renewBeforeDays && certificate.renewBeforeDays > 0 + ); return (
{certificate.commonName}Status Not Before Not AfterAuto RenewalRenewal Status