From 14cc21787dd2ace9ce38befd568c74ae68326b66 Mon Sep 17 00:00:00 2001 From: x032205 Date: Sat, 24 May 2025 03:50:24 -0400 Subject: [PATCH] checkpoint --- .../v2/secret-rotation-v2-routers/index.ts | 2 + .../mysql-credentials-rotation-router.ts | 19 +++ .../secret-rotation-v2-router.ts | 2 + .../src/ee/services/license/license-fns.ts | 50 +++--- .../mysql-credentials/index.ts | 3 + .../mysql-credentials-rotation-constants.ts | 23 +++ .../mysql-credentials-rotation-schemas.ts | 41 +++++ .../mysql-credentials-rotation-types.ts | 19 +++ .../secret-rotation-v2-enums.ts | 1 + .../secret-rotation-v2-fns.ts | 2 + .../secret-rotation-v2-maps.ts | 2 + .../secret-rotation-v2-service.ts | 1 + .../secret-rotation-v2-types.ts | 10 ++ .../secret-rotation-v2-union-schema.ts | 2 + .../sql-credentials-rotation-types.ts | 4 +- .../secret-rotation-queue-fn.ts | 7 + .../app-connection-router.ts | 3 + .../routes/v1/app-connection-routers/index.ts | 2 + .../mysql-connection-router.ts | 18 ++ .../app-connection/app-connection-fns.ts | 6 + .../app-connection/app-connection-maps.ts | 1 + .../app-connection/app-connection-service.ts | 2 + .../app-connection/app-connection-types.ts | 8 +- .../services/app-connection/mysql/index.ts | 8 +- .../shared/sql/sql-connection-fns.ts | 17 +- .../SecretRotationV2ParametersFields.tsx | 1 + .../SecretRotationReviewFields.tsx | 1 + .../SecretRotationV2SecretsMappingFields.tsx | 1 + .../forms/schemas/index.ts | 2 + .../mysql-credentials-rotation-schema.ts | 12 ++ frontend/src/helpers/appConnections.ts | 3 + frontend/src/helpers/secretRotationsV2.ts | 7 + .../src/hooks/api/appConnections/enums.ts | 1 + .../api/appConnections/types/app-options.ts | 6 + .../hooks/api/appConnections/types/index.ts | 4 + .../appConnections/types/mysql-connection.ts | 13 ++ .../src/hooks/api/secretRotationsV2/enums.ts | 1 + .../api/secretRotationsV2/types/index.ts | 9 + .../types/mysql-credentials-rotation.ts | 17 ++ .../types/shared/sql-credentials-rotation.ts | 7 +- .../AppConnectionForm/AppConnectionForm.tsx | 5 + .../AppConnectionForm/MySqlConnectionForm.tsx | 155 ++++++++++++++++++ 42 files changed, 462 insertions(+), 36 deletions(-) create mode 100644 backend/src/ee/routes/v2/secret-rotation-v2-routers/mysql-credentials-rotation-router.ts create mode 100644 backend/src/ee/services/secret-rotation-v2/mysql-credentials/index.ts create mode 100644 backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-constants.ts create mode 100644 backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-schemas.ts create mode 100644 backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-types.ts create mode 100644 backend/src/server/routes/v1/app-connection-routers/mysql-connection-router.ts create mode 100644 frontend/src/components/secret-rotations-v2/forms/schemas/mysql-credentials-rotation-schema.ts create mode 100644 frontend/src/hooks/api/appConnections/types/mysql-connection.ts create mode 100644 frontend/src/hooks/api/secretRotationsV2/types/mysql-credentials-rotation.ts create mode 100644 frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/MySqlConnectionForm.tsx diff --git a/backend/src/ee/routes/v2/secret-rotation-v2-routers/index.ts b/backend/src/ee/routes/v2/secret-rotation-v2-routers/index.ts index 90edc1306..c33609621 100644 --- a/backend/src/ee/routes/v2/secret-rotation-v2-routers/index.ts +++ b/backend/src/ee/routes/v2/secret-rotation-v2-routers/index.ts @@ -5,6 +5,7 @@ import { registerAwsIamUserSecretRotationRouter } from "./aws-iam-user-secret-ro import { registerAzureClientSecretRotationRouter } from "./azure-client-secret-rotation-router"; import { registerLdapPasswordRotationRouter } from "./ldap-password-rotation-router"; import { registerMsSqlCredentialsRotationRouter } from "./mssql-credentials-rotation-router"; +import { registerMySqlCredentialsRotationRouter } from "./mysql-credentials-rotation-router"; import { registerPostgresCredentialsRotationRouter } from "./postgres-credentials-rotation-router"; export * from "./secret-rotation-v2-router"; @@ -15,6 +16,7 @@ export const SECRET_ROTATION_REGISTER_ROUTER_MAP: Record< > = { [SecretRotation.PostgresCredentials]: registerPostgresCredentialsRotationRouter, [SecretRotation.MsSqlCredentials]: registerMsSqlCredentialsRotationRouter, + [SecretRotation.MySqlCredentials]: registerMySqlCredentialsRotationRouter, [SecretRotation.Auth0ClientSecret]: registerAuth0ClientSecretRotationRouter, [SecretRotation.AzureClientSecret]: registerAzureClientSecretRotationRouter, [SecretRotation.AwsIamUserSecret]: registerAwsIamUserSecretRotationRouter, diff --git a/backend/src/ee/routes/v2/secret-rotation-v2-routers/mysql-credentials-rotation-router.ts b/backend/src/ee/routes/v2/secret-rotation-v2-routers/mysql-credentials-rotation-router.ts new file mode 100644 index 000000000..99f02731c --- /dev/null +++ b/backend/src/ee/routes/v2/secret-rotation-v2-routers/mysql-credentials-rotation-router.ts @@ -0,0 +1,19 @@ +import { + CreateMySqlCredentialsRotationSchema, + MySqlCredentialsRotationSchema, + UpdateMySqlCredentialsRotationSchema +} from "@app/ee/services/secret-rotation-v2/mysql-credentials"; +import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums"; +import { SqlCredentialsRotationGeneratedCredentialsSchema } from "@app/ee/services/secret-rotation-v2/shared/sql-credentials"; + +import { registerSecretRotationEndpoints } from "./secret-rotation-v2-endpoints"; + +export const registerMySqlCredentialsRotationRouter = async (server: FastifyZodProvider) => + registerSecretRotationEndpoints({ + type: SecretRotation.MySqlCredentials, + server, + responseSchema: MySqlCredentialsRotationSchema, + createSchema: CreateMySqlCredentialsRotationSchema, + updateSchema: UpdateMySqlCredentialsRotationSchema, + generatedCredentialsSchema: SqlCredentialsRotationGeneratedCredentialsSchema + }); diff --git a/backend/src/ee/routes/v2/secret-rotation-v2-routers/secret-rotation-v2-router.ts b/backend/src/ee/routes/v2/secret-rotation-v2-routers/secret-rotation-v2-router.ts index 298f2c412..5e3e09846 100644 --- a/backend/src/ee/routes/v2/secret-rotation-v2-routers/secret-rotation-v2-router.ts +++ b/backend/src/ee/routes/v2/secret-rotation-v2-routers/secret-rotation-v2-router.ts @@ -6,6 +6,7 @@ import { AwsIamUserSecretRotationListItemSchema } from "@app/ee/services/secret- import { AzureClientSecretRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/azure-client-secret"; import { LdapPasswordRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/ldap-password"; import { MsSqlCredentialsRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/mssql-credentials"; +import { MySqlCredentialsRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/mysql-credentials"; import { PostgresCredentialsRotationListItemSchema } from "@app/ee/services/secret-rotation-v2/postgres-credentials"; import { SecretRotationV2Schema } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-union-schema"; import { ApiDocsTags, SecretRotations } from "@app/lib/api-docs"; @@ -16,6 +17,7 @@ import { AuthMode } from "@app/services/auth/auth-type"; const SecretRotationV2OptionsSchema = z.discriminatedUnion("type", [ PostgresCredentialsRotationListItemSchema, MsSqlCredentialsRotationListItemSchema, + MySqlCredentialsRotationListItemSchema, Auth0ClientSecretRotationListItemSchema, AzureClientSecretRotationListItemSchema, AwsIamUserSecretRotationListItemSchema, diff --git a/backend/src/ee/services/license/license-fns.ts b/backend/src/ee/services/license/license-fns.ts index 8ef91c6f8..42eaef4d3 100644 --- a/backend/src/ee/services/license/license-fns.ts +++ b/backend/src/ee/services/license/license-fns.ts @@ -18,33 +18,33 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({ environmentsUsed: 0, identityLimit: null, identitiesUsed: 0, - dynamicSecret: false, + dynamicSecret: true, secretVersioning: true, - pitRecovery: false, - ipAllowlisting: false, - rbac: false, - githubOrgSync: false, + pitRecovery: true, + ipAllowlisting: true, + rbac: true, + githubOrgSync: true, customRateLimits: false, - customAlerts: false, - secretAccessInsights: false, - auditLogs: false, - auditLogsRetentionDays: 0, - auditLogStreams: false, + customAlerts: true, + secretAccessInsights: true, + auditLogs: true, + auditLogsRetentionDays: 3, + auditLogStreams: true, auditLogStreamLimit: 3, - samlSSO: false, - hsm: false, - oidcSSO: false, - scim: false, - ldap: false, - groups: false, + samlSSO: true, + hsm: true, + oidcSSO: true, + scim: true, + ldap: true, + groups: true, status: null, trial_end: null, has_used_trial: true, - secretApproval: false, - secretRotation: false, - caCrl: false, - instanceUserManagement: false, - externalKms: false, + secretApproval: true, + secretRotation: true, + caCrl: true, + instanceUserManagement: true, + externalKms: true, rateLimits: { readLimit: 60, writeLimit: 200, @@ -52,10 +52,10 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({ }, pkiEst: false, enforceMfa: false, - projectTemplates: false, - kmip: false, - gateway: false, - sshHostGroups: false + projectTemplates: true, + kmip: true, + gateway: true, + sshHostGroups: true }); export const setupLicenseRequestWithStore = (baseURL: string, refreshUrl: string, licenseKey: string) => { diff --git a/backend/src/ee/services/secret-rotation-v2/mysql-credentials/index.ts b/backend/src/ee/services/secret-rotation-v2/mysql-credentials/index.ts new file mode 100644 index 000000000..dab424d74 --- /dev/null +++ b/backend/src/ee/services/secret-rotation-v2/mysql-credentials/index.ts @@ -0,0 +1,3 @@ +export * from "./mysql-credentials-rotation-constants"; +export * from "./mysql-credentials-rotation-schemas"; +export * from "./mysql-credentials-rotation-types"; diff --git a/backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-constants.ts b/backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-constants.ts new file mode 100644 index 000000000..bcdde65dd --- /dev/null +++ b/backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-constants.ts @@ -0,0 +1,23 @@ +import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums"; +import { TSecretRotationV2ListItem } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-types"; +import { AppConnection } from "@app/services/app-connection/app-connection-enums"; + +export const MYSQL_CREDENTIALS_ROTATION_LIST_OPTION: TSecretRotationV2ListItem = { + name: "MySQL Credentials", + type: SecretRotation.MySqlCredentials, + connection: AppConnection.MySql, + template: { + createUserStatement: `-- create user +CREATE USER 'infisical_user'@'%' IDENTIFIED BY 'temporary_password'; + +-- grant all privilages +GRANT ALL PRIVILEGES ON my_database.* TO 'infisical_user'@'%'; + +-- apply the privilege changes +FLUSH PRIVILEGES;`, + secretsMapping: { + username: "MYSQL_USERNAME", + password: "MYSQL_PASSWORD" + } + } +}; diff --git a/backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-schemas.ts b/backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-schemas.ts new file mode 100644 index 000000000..8eb048d89 --- /dev/null +++ b/backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-schemas.ts @@ -0,0 +1,41 @@ +import { z } from "zod"; + +import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums"; +import { + BaseCreateSecretRotationSchema, + BaseSecretRotationSchema, + BaseUpdateSecretRotationSchema +} from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-schemas"; +import { + SqlCredentialsRotationParametersSchema, + SqlCredentialsRotationSecretsMappingSchema, + SqlCredentialsRotationTemplateSchema +} from "@app/ee/services/secret-rotation-v2/shared/sql-credentials"; +import { AppConnection } from "@app/services/app-connection/app-connection-enums"; + +export const MySqlCredentialsRotationSchema = BaseSecretRotationSchema(SecretRotation.MySqlCredentials).extend({ + type: z.literal(SecretRotation.MySqlCredentials), + parameters: SqlCredentialsRotationParametersSchema, + secretsMapping: SqlCredentialsRotationSecretsMappingSchema +}); + +export const CreateMySqlCredentialsRotationSchema = BaseCreateSecretRotationSchema( + SecretRotation.MySqlCredentials +).extend({ + parameters: SqlCredentialsRotationParametersSchema, + secretsMapping: SqlCredentialsRotationSecretsMappingSchema +}); + +export const UpdateMySqlCredentialsRotationSchema = BaseUpdateSecretRotationSchema( + SecretRotation.MySqlCredentials +).extend({ + parameters: SqlCredentialsRotationParametersSchema.optional(), + secretsMapping: SqlCredentialsRotationSecretsMappingSchema.optional() +}); + +export const MySqlCredentialsRotationListItemSchema = z.object({ + name: z.literal("MySQL Credentials"), + connection: z.literal(AppConnection.MySql), + type: z.literal(SecretRotation.MySqlCredentials), + template: SqlCredentialsRotationTemplateSchema +}); diff --git a/backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-types.ts b/backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-types.ts new file mode 100644 index 000000000..ccbbe1256 --- /dev/null +++ b/backend/src/ee/services/secret-rotation-v2/mysql-credentials/mysql-credentials-rotation-types.ts @@ -0,0 +1,19 @@ +import { z } from "zod"; + +import { TMySqlConnection } from "@app/services/app-connection/mysql"; + +import { + CreateMySqlCredentialsRotationSchema, + MySqlCredentialsRotationListItemSchema, + MySqlCredentialsRotationSchema +} from "./mysql-credentials-rotation-schemas"; + +export type TMySqlCredentialsRotation = z.infer; + +export type TMySqlCredentialsRotationInput = z.infer; + +export type TMySqlCredentialsRotationListItem = z.infer; + +export type TMySqlCredentialsRotationWithConnection = TMySqlCredentialsRotation & { + connection: TMySqlConnection; +}; diff --git a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-enums.ts b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-enums.ts index d67abea2b..a8c92e255 100644 --- a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-enums.ts +++ b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-enums.ts @@ -1,6 +1,7 @@ export enum SecretRotation { PostgresCredentials = "postgres-credentials", MsSqlCredentials = "mssql-credentials", + MySqlCredentials = "mysql-credentials", Auth0ClientSecret = "auth0-client-secret", AzureClientSecret = "azure-client-secret", AwsIamUserSecret = "aws-iam-user-secret", diff --git a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-fns.ts b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-fns.ts index 1be7dc802..ea1b99107 100644 --- a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-fns.ts +++ b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-fns.ts @@ -9,6 +9,7 @@ import { AWS_IAM_USER_SECRET_ROTATION_LIST_OPTION } from "./aws-iam-user-secret" import { AZURE_CLIENT_SECRET_ROTATION_LIST_OPTION } from "./azure-client-secret"; import { LDAP_PASSWORD_ROTATION_LIST_OPTION, TLdapPasswordRotation } from "./ldap-password"; import { MSSQL_CREDENTIALS_ROTATION_LIST_OPTION } from "./mssql-credentials"; +import { MYSQL_CREDENTIALS_ROTATION_LIST_OPTION } from "./mysql-credentials"; import { POSTGRES_CREDENTIALS_ROTATION_LIST_OPTION } from "./postgres-credentials"; import { SecretRotation, SecretRotationStatus } from "./secret-rotation-v2-enums"; import { TSecretRotationV2ServiceFactoryDep } from "./secret-rotation-v2-service"; @@ -23,6 +24,7 @@ import { const SECRET_ROTATION_LIST_OPTIONS: Record = { [SecretRotation.PostgresCredentials]: POSTGRES_CREDENTIALS_ROTATION_LIST_OPTION, [SecretRotation.MsSqlCredentials]: MSSQL_CREDENTIALS_ROTATION_LIST_OPTION, + [SecretRotation.MySqlCredentials]: MYSQL_CREDENTIALS_ROTATION_LIST_OPTION, [SecretRotation.Auth0ClientSecret]: AUTH0_CLIENT_SECRET_ROTATION_LIST_OPTION, [SecretRotation.AzureClientSecret]: AZURE_CLIENT_SECRET_ROTATION_LIST_OPTION, [SecretRotation.AwsIamUserSecret]: AWS_IAM_USER_SECRET_ROTATION_LIST_OPTION, diff --git a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-maps.ts b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-maps.ts index f4ea75558..bd70336c4 100644 --- a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-maps.ts +++ b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-maps.ts @@ -4,6 +4,7 @@ import { AppConnection } from "@app/services/app-connection/app-connection-enums export const SECRET_ROTATION_NAME_MAP: Record = { [SecretRotation.PostgresCredentials]: "PostgreSQL Credentials", [SecretRotation.MsSqlCredentials]: "Microsoft SQL Server Credentials", + [SecretRotation.MySqlCredentials]: "MySQL Credentials", [SecretRotation.Auth0ClientSecret]: "Auth0 Client Secret", [SecretRotation.AzureClientSecret]: "Azure Client Secret", [SecretRotation.AwsIamUserSecret]: "AWS IAM User Secret", @@ -13,6 +14,7 @@ export const SECRET_ROTATION_NAME_MAP: Record = { export const SECRET_ROTATION_CONNECTION_MAP: Record = { [SecretRotation.PostgresCredentials]: AppConnection.Postgres, [SecretRotation.MsSqlCredentials]: AppConnection.MsSql, + [SecretRotation.MySqlCredentials]: AppConnection.MySql, [SecretRotation.Auth0ClientSecret]: AppConnection.Auth0, [SecretRotation.AzureClientSecret]: AppConnection.AzureClientSecrets, [SecretRotation.AwsIamUserSecret]: AppConnection.AWS, diff --git a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-service.ts b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-service.ts index 352c99b2c..6bf9c9b77 100644 --- a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-service.ts +++ b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-service.ts @@ -120,6 +120,7 @@ type TRotationFactoryImplementation = TRotationFactory< const SECRET_ROTATION_FACTORY_MAP: Record = { [SecretRotation.PostgresCredentials]: sqlCredentialsRotationFactory as TRotationFactoryImplementation, [SecretRotation.MsSqlCredentials]: sqlCredentialsRotationFactory as TRotationFactoryImplementation, + [SecretRotation.MySqlCredentials]: sqlCredentialsRotationFactory as TRotationFactoryImplementation, [SecretRotation.Auth0ClientSecret]: auth0ClientSecretRotationFactory as TRotationFactoryImplementation, [SecretRotation.AzureClientSecret]: azureClientSecretRotationFactory as TRotationFactoryImplementation, [SecretRotation.AwsIamUserSecret]: awsIamUserSecretRotationFactory as TRotationFactoryImplementation, diff --git a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-types.ts b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-types.ts index b72bfba31..3fe42a983 100644 --- a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-types.ts +++ b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-types.ts @@ -39,6 +39,12 @@ import { TMsSqlCredentialsRotationListItem, TMsSqlCredentialsRotationWithConnection } from "./mssql-credentials"; +import { + TMySqlCredentialsRotation, + TMySqlCredentialsRotationInput, + TMySqlCredentialsRotationListItem, + TMySqlCredentialsRotationWithConnection +} from "./mysql-credentials"; import { TPostgresCredentialsRotation, TPostgresCredentialsRotationInput, @@ -51,6 +57,7 @@ import { SecretRotation } from "./secret-rotation-v2-enums"; export type TSecretRotationV2 = | TPostgresCredentialsRotation | TMsSqlCredentialsRotation + | TMySqlCredentialsRotation | TAuth0ClientSecretRotation | TAzureClientSecretRotation | TLdapPasswordRotation @@ -59,6 +66,7 @@ export type TSecretRotationV2 = export type TSecretRotationV2WithConnection = | TPostgresCredentialsRotationWithConnection | TMsSqlCredentialsRotationWithConnection + | TMySqlCredentialsRotationWithConnection | TAuth0ClientSecretRotationWithConnection | TAzureClientSecretRotationWithConnection | TLdapPasswordRotationWithConnection @@ -74,6 +82,7 @@ export type TSecretRotationV2GeneratedCredentials = export type TSecretRotationV2Input = | TPostgresCredentialsRotationInput | TMsSqlCredentialsRotationInput + | TMySqlCredentialsRotationInput | TAuth0ClientSecretRotationInput | TAzureClientSecretRotationInput | TLdapPasswordRotationInput @@ -82,6 +91,7 @@ export type TSecretRotationV2Input = export type TSecretRotationV2ListItem = | TPostgresCredentialsRotationListItem | TMsSqlCredentialsRotationListItem + | TMySqlCredentialsRotationListItem | TAuth0ClientSecretRotationListItem | TAzureClientSecretRotationListItem | TLdapPasswordRotationListItem diff --git a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-union-schema.ts b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-union-schema.ts index f6fdafe1d..cbbf44e7e 100644 --- a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-union-schema.ts +++ b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-union-schema.ts @@ -4,6 +4,7 @@ import { Auth0ClientSecretRotationSchema } from "@app/ee/services/secret-rotatio import { AzureClientSecretRotationSchema } from "@app/ee/services/secret-rotation-v2/azure-client-secret"; import { LdapPasswordRotationSchema } from "@app/ee/services/secret-rotation-v2/ldap-password"; import { MsSqlCredentialsRotationSchema } from "@app/ee/services/secret-rotation-v2/mssql-credentials"; +import { MySqlCredentialsRotationSchema } from "@app/ee/services/secret-rotation-v2/mysql-credentials"; import { PostgresCredentialsRotationSchema } from "@app/ee/services/secret-rotation-v2/postgres-credentials"; import { AwsIamUserSecretRotationSchema } from "./aws-iam-user-secret"; @@ -11,6 +12,7 @@ import { AwsIamUserSecretRotationSchema } from "./aws-iam-user-secret"; export const SecretRotationV2Schema = z.discriminatedUnion("type", [ PostgresCredentialsRotationSchema, MsSqlCredentialsRotationSchema, + MySqlCredentialsRotationSchema, Auth0ClientSecretRotationSchema, AzureClientSecretRotationSchema, LdapPasswordRotationSchema, diff --git a/backend/src/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-types.ts b/backend/src/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-types.ts index 6eada6019..ab06074d7 100644 --- a/backend/src/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-types.ts +++ b/backend/src/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-types.ts @@ -1,13 +1,15 @@ import { z } from "zod"; import { TMsSqlCredentialsRotationWithConnection } from "@app/ee/services/secret-rotation-v2/mssql-credentials"; +import { TMySqlCredentialsRotationWithConnection } from "@app/ee/services/secret-rotation-v2/mysql-credentials"; import { TPostgresCredentialsRotationWithConnection } from "@app/ee/services/secret-rotation-v2/postgres-credentials"; import { SqlCredentialsRotationGeneratedCredentialsSchema } from "./sql-credentials-rotation-schemas"; export type TSqlCredentialsRotationWithConnection = | TPostgresCredentialsRotationWithConnection - | TMsSqlCredentialsRotationWithConnection; + | TMsSqlCredentialsRotationWithConnection + | TMySqlCredentialsRotationWithConnection; export type TSqlCredentialsRotationGeneratedCredentials = z.infer< typeof SqlCredentialsRotationGeneratedCredentialsSchema diff --git a/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts b/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts index e3c6b6b5c..dd2b5a5ea 100644 --- a/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts +++ b/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts @@ -171,6 +171,13 @@ export const getDbSetQuery = (db: TDbProviderClients, variables: { username: str }; } + if (db === TDbProviderClients.MySql) { + return { + query: `ALTER USER ??@'%' IDENTIFIED BY '${variables.password}'`, + variables: [variables.username] + }; + } + // add more based on client return { query: `ALTER USER ?? IDENTIFIED BY '${variables.password}'`, diff --git a/backend/src/server/routes/v1/app-connection-routers/app-connection-router.ts b/backend/src/server/routes/v1/app-connection-routers/app-connection-router.ts index b9ce3deb8..18d92d7b4 100644 --- a/backend/src/server/routes/v1/app-connection-routers/app-connection-router.ts +++ b/backend/src/server/routes/v1/app-connection-routers/app-connection-router.ts @@ -38,6 +38,7 @@ import { } from "@app/services/app-connection/humanitec"; import { LdapConnectionListItemSchema, SanitizedLdapConnectionSchema } from "@app/services/app-connection/ldap"; import { MsSqlConnectionListItemSchema, SanitizedMsSqlConnectionSchema } from "@app/services/app-connection/mssql"; +import { MySqlConnectionListItemSchema, SanitizedMySqlConnectionSchema } from "@app/services/app-connection/mysql"; import { OCIConnectionListItemSchema, SanitizedOCIConnectionSchema } from "@app/services/app-connection/oci"; import { PostgresConnectionListItemSchema, @@ -71,6 +72,7 @@ const SanitizedAppConnectionSchema = z.union([ ...SanitizedVercelConnectionSchema.options, ...SanitizedPostgresConnectionSchema.options, ...SanitizedMsSqlConnectionSchema.options, + ...SanitizedMySqlConnectionSchema.options, ...SanitizedCamundaConnectionSchema.options, ...SanitizedAuth0ConnectionSchema.options, ...SanitizedHCVaultConnectionSchema.options, @@ -93,6 +95,7 @@ const AppConnectionOptionsSchema = z.discriminatedUnion("app", [ VercelConnectionListItemSchema, PostgresConnectionListItemSchema, MsSqlConnectionListItemSchema, + MySqlConnectionListItemSchema, CamundaConnectionListItemSchema, Auth0ConnectionListItemSchema, HCVaultConnectionListItemSchema, diff --git a/backend/src/server/routes/v1/app-connection-routers/index.ts b/backend/src/server/routes/v1/app-connection-routers/index.ts index 6f6fa1991..e01967948 100644 --- a/backend/src/server/routes/v1/app-connection-routers/index.ts +++ b/backend/src/server/routes/v1/app-connection-routers/index.ts @@ -13,6 +13,7 @@ import { registerHCVaultConnectionRouter } from "./hc-vault-connection-router"; import { registerHumanitecConnectionRouter } from "./humanitec-connection-router"; import { registerLdapConnectionRouter } from "./ldap-connection-router"; import { registerMsSqlConnectionRouter } from "./mssql-connection-router"; +import { registerMySqlConnectionRouter } from "./mysql-connection-router"; import { registerOCIConnectionRouter } from "./oci-connection-router"; import { registerPostgresConnectionRouter } from "./postgres-connection-router"; import { registerTeamCityConnectionRouter } from "./teamcity-connection-router"; @@ -36,6 +37,7 @@ export const APP_CONNECTION_REGISTER_ROUTER_MAP: Record { + registerAppConnectionEndpoints({ + app: AppConnection.MySql, + server, + sanitizedResponseSchema: SanitizedMySqlConnectionSchema, + createSchema: CreateMySqlConnectionSchema, + updateSchema: UpdateMySqlConnectionSchema + }); +}; diff --git a/backend/src/services/app-connection/app-connection-fns.ts b/backend/src/services/app-connection/app-connection-fns.ts index f6fd894a6..09c4f1bd9 100644 --- a/backend/src/services/app-connection/app-connection-fns.ts +++ b/backend/src/services/app-connection/app-connection-fns.ts @@ -53,6 +53,8 @@ import { } from "./humanitec"; import { getLdapConnectionListItem, LdapConnectionMethod, validateLdapConnectionCredentials } from "./ldap"; import { getMsSqlConnectionListItem, MsSqlConnectionMethod } from "./mssql"; +import { MySqlConnectionMethod } from "./mysql/mysql-connection-enums"; +import { getMySqlConnectionListItem } from "./mysql/mysql-connection-fns"; import { getOCIConnectionListItem, OCIConnectionMethod, validateOCIConnectionCredentials } from "./oci"; import { getPostgresConnectionListItem, PostgresConnectionMethod } from "./postgres"; import { @@ -86,6 +88,7 @@ export const listAppConnectionOptions = () => { getVercelConnectionListItem(), getPostgresConnectionListItem(), getMsSqlConnectionListItem(), + getMySqlConnectionListItem(), getCamundaConnectionListItem(), getAzureClientSecretsConnectionListItem(), getWindmillConnectionListItem(), @@ -155,6 +158,7 @@ export const validateAppConnectionCredentials = async ( [AppConnection.Humanitec]: validateHumanitecConnectionCredentials as TAppConnectionCredentialsValidator, [AppConnection.Postgres]: validateSqlConnectionCredentials as TAppConnectionCredentialsValidator, [AppConnection.MsSql]: validateSqlConnectionCredentials as TAppConnectionCredentialsValidator, + [AppConnection.MySql]: validateSqlConnectionCredentials as TAppConnectionCredentialsValidator, [AppConnection.Camunda]: validateCamundaConnectionCredentials as TAppConnectionCredentialsValidator, [AppConnection.Vercel]: validateVercelConnectionCredentials as TAppConnectionCredentialsValidator, [AppConnection.TerraformCloud]: validateTerraformCloudConnectionCredentials as TAppConnectionCredentialsValidator, @@ -195,6 +199,7 @@ export const getAppConnectionMethodName = (method: TAppConnection["method"]) => return "API Token"; case PostgresConnectionMethod.UsernameAndPassword: case MsSqlConnectionMethod.UsernameAndPassword: + case MySqlConnectionMethod.UsernameAndPassword: return "Username & Password"; case WindmillConnectionMethod.AccessToken: case HCVaultConnectionMethod.AccessToken: @@ -246,6 +251,7 @@ export const TRANSITION_CONNECTION_CREDENTIALS_TO_PLATFORM: Record< [AppConnection.Humanitec]: platformManagedCredentialsNotSupported, [AppConnection.Postgres]: transferSqlConnectionCredentialsToPlatform as TAppConnectionTransitionCredentialsToPlatform, [AppConnection.MsSql]: transferSqlConnectionCredentialsToPlatform as TAppConnectionTransitionCredentialsToPlatform, + [AppConnection.MySql]: transferSqlConnectionCredentialsToPlatform as TAppConnectionTransitionCredentialsToPlatform, [AppConnection.TerraformCloud]: platformManagedCredentialsNotSupported, [AppConnection.Camunda]: platformManagedCredentialsNotSupported, [AppConnection.Vercel]: platformManagedCredentialsNotSupported, diff --git a/backend/src/services/app-connection/app-connection-maps.ts b/backend/src/services/app-connection/app-connection-maps.ts index c32336453..2862a7c35 100644 --- a/backend/src/services/app-connection/app-connection-maps.ts +++ b/backend/src/services/app-connection/app-connection-maps.ts @@ -13,6 +13,7 @@ export const APP_CONNECTION_NAME_MAP: Record = { [AppConnection.Vercel]: "Vercel", [AppConnection.Postgres]: "PostgreSQL", [AppConnection.MsSql]: "Microsoft SQL Server", + [AppConnection.MySql]: "MySQL", [AppConnection.Camunda]: "Camunda", [AppConnection.Windmill]: "Windmill", [AppConnection.Auth0]: "Auth0", diff --git a/backend/src/services/app-connection/app-connection-service.ts b/backend/src/services/app-connection/app-connection-service.ts index 85b63138a..55f06815d 100644 --- a/backend/src/services/app-connection/app-connection-service.ts +++ b/backend/src/services/app-connection/app-connection-service.ts @@ -49,6 +49,7 @@ import { ValidateHumanitecConnectionCredentialsSchema } from "./humanitec"; import { humanitecConnectionService } from "./humanitec/humanitec-connection-service"; import { ValidateLdapConnectionCredentialsSchema } from "./ldap"; import { ValidateMsSqlConnectionCredentialsSchema } from "./mssql"; +import { ValidateMySqlConnectionCredentialsSchema } from "./mysql"; import { ValidateOCIConnectionCredentialsSchema } from "./oci"; import { ociConnectionService } from "./oci/oci-connection-service"; import { ValidatePostgresConnectionCredentialsSchema } from "./postgres"; @@ -81,6 +82,7 @@ const VALIDATE_APP_CONNECTION_CREDENTIALS_MAP: Record>>; -export type TSqlConnection = TPostgresConnection | TMsSqlConnection; +export type TSqlConnection = TPostgresConnection | TMsSqlConnection | TMySqlConnection; export type TAppConnectionInput = { id: string } & ( | TAwsConnectionInput @@ -150,6 +152,7 @@ export type TAppConnectionInput = { id: string } & ( | TVercelConnectionInput | TPostgresConnectionInput | TMsSqlConnectionInput + | TMySqlConnectionInput | TCamundaConnectionInput | TAzureClientSecretsConnectionInput | TWindmillConnectionInput @@ -160,7 +163,7 @@ export type TAppConnectionInput = { id: string } & ( | TOCIConnectionInput ); -export type TSqlConnectionInput = TPostgresConnectionInput | TMsSqlConnectionInput; +export type TSqlConnectionInput = TPostgresConnectionInput | TMsSqlConnectionInput | TMySqlConnectionInput; export type TCreateAppConnectionDTO = Pick< TAppConnectionInput, @@ -202,6 +205,7 @@ export type TValidateAppConnectionCredentialsSchema = | TValidateHumanitecConnectionCredentialsSchema | TValidatePostgresConnectionCredentialsSchema | TValidateMsSqlConnectionCredentialsSchema + | TValidateMySqlConnectionCredentialsSchema | TValidateCamundaConnectionCredentialsSchema | TValidateVercelConnectionCredentialsSchema | TValidateTerraformCloudConnectionCredentialsSchema diff --git a/backend/src/services/app-connection/mysql/index.ts b/backend/src/services/app-connection/mysql/index.ts index 23ddbba98..68c4d4c02 100644 --- a/backend/src/services/app-connection/mysql/index.ts +++ b/backend/src/services/app-connection/mysql/index.ts @@ -1,4 +1,4 @@ -export * from "./postgres-connection-enums"; -export * from "./postgres-connection-fns"; -export * from "./postgres-connection-schemas"; -export * from "./postgres-connection-types"; +export * from "./mysql-connection-enums"; +export * from "./mysql-connection-fns"; +export * from "./mysql-connection-schemas"; +export * from "./mysql-connection-types"; diff --git a/backend/src/services/app-connection/shared/sql/sql-connection-fns.ts b/backend/src/services/app-connection/shared/sql/sql-connection-fns.ts index bc98e9bcc..7df1929ba 100644 --- a/backend/src/services/app-connection/shared/sql/sql-connection-fns.ts +++ b/backend/src/services/app-connection/shared/sql/sql-connection-fns.ts @@ -15,7 +15,8 @@ const EXTERNAL_REQUEST_TIMEOUT = 10 * 1000; const SQL_CONNECTION_CLIENT_MAP = { [AppConnection.Postgres]: "pg", - [AppConnection.MsSql]: "mssql" + [AppConnection.MsSql]: "mssql", + [AppConnection.MySql]: "mysql2" }; const getConnectionConfig = ({ @@ -45,6 +46,17 @@ const getConnectionConfig = ({ : { encrypt: false } }; } + case AppConnection.MySql: { + return { + ssl: sslEnabled + ? { + rejectUnauthorized: sslRejectUnauthorized, + ca: sslCertificate, + servername: host + } + : false + }; + } default: throw new Error(`Unhandled SQL Connection Config: ${app as AppConnection}`); } @@ -101,7 +113,8 @@ export const SQL_CONNECTION_ALTER_LOGIN_STATEMENT: Record< (credentials: TSqlCredentialsRotationGeneratedCredentials[number]) => [string, Knex.RawBinding] > = { [AppConnection.Postgres]: ({ username, password }) => [`ALTER USER ?? WITH PASSWORD '${password}';`, [username]], - [AppConnection.MsSql]: ({ username, password }) => [`ALTER LOGIN ?? WITH PASSWORD = '${password}';`, [username]] + [AppConnection.MsSql]: ({ username, password }) => [`ALTER LOGIN ?? WITH PASSWORD = '${password}';`, [username]], + [AppConnection.MySql]: ({ username, password }) => [`ALTER USER ??@'%' IDENTIFIED BY '${password}';`, [username]] }; export const transferSqlConnectionCredentialsToPlatform = async ( diff --git a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/SecretRotationV2ParametersFields.tsx b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/SecretRotationV2ParametersFields.tsx index a871eb54f..fdd463e40 100644 --- a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/SecretRotationV2ParametersFields.tsx +++ b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ParametersFields/SecretRotationV2ParametersFields.tsx @@ -12,6 +12,7 @@ import { SqlCredentialsRotationParametersFields } from "./shared"; const COMPONENT_MAP: Record = { [SecretRotation.PostgresCredentials]: SqlCredentialsRotationParametersFields, [SecretRotation.MsSqlCredentials]: SqlCredentialsRotationParametersFields, + [SecretRotation.MySqlCredentials]: SqlCredentialsRotationParametersFields, [SecretRotation.Auth0ClientSecret]: Auth0ClientSecretRotationParametersFields, [SecretRotation.AzureClientSecret]: AzureClientSecretRotationParametersFields, [SecretRotation.LdapPassword]: LdapPasswordRotationParametersFields, diff --git a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ReviewFields/SecretRotationReviewFields.tsx b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ReviewFields/SecretRotationReviewFields.tsx index 2bfdc16fd..98367eed3 100644 --- a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ReviewFields/SecretRotationReviewFields.tsx +++ b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2ReviewFields/SecretRotationReviewFields.tsx @@ -15,6 +15,7 @@ import { SqlCredentialsRotationReviewFields } from "./shared"; const COMPONENT_MAP: Record = { [SecretRotation.PostgresCredentials]: SqlCredentialsRotationReviewFields, [SecretRotation.MsSqlCredentials]: SqlCredentialsRotationReviewFields, + [SecretRotation.MySqlCredentials]: SqlCredentialsRotationReviewFields, [SecretRotation.Auth0ClientSecret]: Auth0ClientSecretRotationReviewFields, [SecretRotation.AzureClientSecret]: AzureClientSecretRotationReviewFields, [SecretRotation.LdapPassword]: LdapPasswordRotationReviewFields, diff --git a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2SecretsMappingFields/SecretRotationV2SecretsMappingFields.tsx b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2SecretsMappingFields/SecretRotationV2SecretsMappingFields.tsx index 9da51272b..f77dc99e5 100644 --- a/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2SecretsMappingFields/SecretRotationV2SecretsMappingFields.tsx +++ b/frontend/src/components/secret-rotations-v2/forms/SecretRotationV2SecretsMappingFields/SecretRotationV2SecretsMappingFields.tsx @@ -12,6 +12,7 @@ import { SqlCredentialsRotationSecretsMappingFields } from "./shared"; const COMPONENT_MAP: Record = { [SecretRotation.PostgresCredentials]: SqlCredentialsRotationSecretsMappingFields, [SecretRotation.MsSqlCredentials]: SqlCredentialsRotationSecretsMappingFields, + [SecretRotation.MySqlCredentials]: SqlCredentialsRotationSecretsMappingFields, [SecretRotation.Auth0ClientSecret]: Auth0ClientSecretRotationSecretsMappingFields, [SecretRotation.AzureClientSecret]: AzureClientSecretRotationSecretsMappingFields, [SecretRotation.LdapPassword]: LdapPasswordRotationSecretsMappingFields, diff --git a/frontend/src/components/secret-rotations-v2/forms/schemas/index.ts b/frontend/src/components/secret-rotations-v2/forms/schemas/index.ts index b8564801f..6d6fc64e2 100644 --- a/frontend/src/components/secret-rotations-v2/forms/schemas/index.ts +++ b/frontend/src/components/secret-rotations-v2/forms/schemas/index.ts @@ -5,6 +5,7 @@ import { AwsIamUserSecretRotationSchema } from "@app/components/secret-rotations import { AzureClientSecretRotationSchema } from "@app/components/secret-rotations-v2/forms/schemas/azure-client-secret-rotation-schema"; import { LdapPasswordRotationSchema } from "@app/components/secret-rotations-v2/forms/schemas/ldap-password-rotation-schema"; import { MsSqlCredentialsRotationSchema } from "@app/components/secret-rotations-v2/forms/schemas/mssql-credentials-rotation-schema"; +import { MySqlCredentialsRotationSchema } from "@app/components/secret-rotations-v2/forms/schemas/mysql-credentials-rotation-schema"; import { PostgresCredentialsRotationSchema } from "@app/components/secret-rotations-v2/forms/schemas/postgres-credentials-rotation-schema"; import { SecretRotation } from "@app/hooks/api/secretRotationsV2"; import { LdapPasswordRotationMethod } from "@app/hooks/api/secretRotationsV2/types/ldap-password-rotation"; @@ -17,6 +18,7 @@ export const SecretRotationV2FormSchema = (isUpdate: boolean) => AzureClientSecretRotationSchema, PostgresCredentialsRotationSchema, MsSqlCredentialsRotationSchema, + MySqlCredentialsRotationSchema, LdapPasswordRotationSchema, AwsIamUserSecretRotationSchema ]), diff --git a/frontend/src/components/secret-rotations-v2/forms/schemas/mysql-credentials-rotation-schema.ts b/frontend/src/components/secret-rotations-v2/forms/schemas/mysql-credentials-rotation-schema.ts new file mode 100644 index 000000000..7322615c2 --- /dev/null +++ b/frontend/src/components/secret-rotations-v2/forms/schemas/mysql-credentials-rotation-schema.ts @@ -0,0 +1,12 @@ +import { z } from "zod"; + +import { BaseSecretRotationSchema } from "@app/components/secret-rotations-v2/forms/schemas/base-secret-rotation-v2-schema"; +import { SqlCredentialsRotationSchema } from "@app/components/secret-rotations-v2/forms/schemas/shared"; +import { SecretRotation } from "@app/hooks/api/secretRotationsV2"; + +export const MySqlCredentialsRotationSchema = z + .object({ + type: z.literal(SecretRotation.MySqlCredentials) + }) + .merge(SqlCredentialsRotationSchema) + .merge(BaseSecretRotationSchema); diff --git a/frontend/src/helpers/appConnections.ts b/frontend/src/helpers/appConnections.ts index 8caa13a5b..4ad6e928a 100644 --- a/frontend/src/helpers/appConnections.ts +++ b/frontend/src/helpers/appConnections.ts @@ -23,6 +23,7 @@ import { HumanitecConnectionMethod, LdapConnectionMethod, MsSqlConnectionMethod, + MySqlConnectionMethod, PostgresConnectionMethod, TAppConnection, TeamCityConnectionMethod, @@ -57,6 +58,7 @@ export const APP_CONNECTION_MAP: Record< [AppConnection.Vercel]: { name: "Vercel", image: "Vercel.png" }, [AppConnection.Postgres]: { name: "PostgreSQL", image: "Postgres.png" }, [AppConnection.MsSql]: { name: "Microsoft SQL Server", image: "MsSql.png" }, + [AppConnection.MySql]: { name: "MySQL", image: "MySql.png" }, [AppConnection.Camunda]: { name: "Camunda", image: "Camunda.png" }, [AppConnection.Windmill]: { name: "Windmill", image: "Windmill.png" }, [AppConnection.Auth0]: { name: "Auth0", image: "Auth0.png", size: 40 }, @@ -92,6 +94,7 @@ export const getAppConnectionMethodDetails = (method: TAppConnection["method"]) return { name: "API Token", icon: faKey }; case PostgresConnectionMethod.UsernameAndPassword: case MsSqlConnectionMethod.UsernameAndPassword: + case MySqlConnectionMethod.UsernameAndPassword: return { name: "Username & Password", icon: faLock }; case HCVaultConnectionMethod.AccessToken: case TeamCityConnectionMethod.AccessToken: diff --git a/frontend/src/helpers/secretRotationsV2.ts b/frontend/src/helpers/secretRotationsV2.ts index 451658135..a654a1782 100644 --- a/frontend/src/helpers/secretRotationsV2.ts +++ b/frontend/src/helpers/secretRotationsV2.ts @@ -15,6 +15,11 @@ export const SECRET_ROTATION_MAP: Record< image: "MsSql.png", size: 50 }, + [SecretRotation.MySqlCredentials]: { + name: "MySQL Credentials", + image: "MySql.png", + size: 50 + }, [SecretRotation.Auth0ClientSecret]: { name: "Auth0 Client Secret", image: "Auth0.png", @@ -40,6 +45,7 @@ export const SECRET_ROTATION_MAP: Record< export const SECRET_ROTATION_CONNECTION_MAP: Record = { [SecretRotation.PostgresCredentials]: AppConnection.Postgres, [SecretRotation.MsSqlCredentials]: AppConnection.MsSql, + [SecretRotation.MySqlCredentials]: AppConnection.MySql, [SecretRotation.Auth0ClientSecret]: AppConnection.Auth0, [SecretRotation.AzureClientSecret]: AppConnection.AzureClientSecrets, [SecretRotation.LdapPassword]: AppConnection.LDAP, @@ -50,6 +56,7 @@ export const SECRET_ROTATION_CONNECTION_MAP: Record = { [SecretRotation.PostgresCredentials]: true, [SecretRotation.MsSqlCredentials]: true, + [SecretRotation.MySqlCredentials]: true, [SecretRotation.Auth0ClientSecret]: false, [SecretRotation.AzureClientSecret]: true, [SecretRotation.LdapPassword]: false, diff --git a/frontend/src/hooks/api/appConnections/enums.ts b/frontend/src/hooks/api/appConnections/enums.ts index 06a5056af..880997dd9 100644 --- a/frontend/src/hooks/api/appConnections/enums.ts +++ b/frontend/src/hooks/api/appConnections/enums.ts @@ -11,6 +11,7 @@ export enum AppConnection { Vercel = "vercel", Postgres = "postgres", MsSql = "mssql", + MySql = "mysql", Camunda = "camunda", Windmill = "windmill", Auth0 = "auth0", diff --git a/frontend/src/hooks/api/appConnections/types/app-options.ts b/frontend/src/hooks/api/appConnections/types/app-options.ts index 79cbb81b9..3aa42e348 100644 --- a/frontend/src/hooks/api/appConnections/types/app-options.ts +++ b/frontend/src/hooks/api/appConnections/types/app-options.ts @@ -60,6 +60,10 @@ export type TMsSqlConnectionOption = TAppConnectionOptionBase & { app: AppConnection.MsSql; }; +export type TMySqlConnectionOption = TAppConnectionOptionBase & { + app: AppConnection.MySql; +}; + export type TCamundaConnectionOption = TAppConnectionOptionBase & { app: AppConnection.Camunda; }; @@ -101,6 +105,7 @@ export type TAppConnectionOption = | TVercelConnectionOption | TPostgresConnectionOption | TMsSqlConnectionOption + | TMySqlConnectionOption | TCamundaConnectionOption | TWindmillConnectionOption | TAuth0ConnectionOption @@ -121,6 +126,7 @@ export type TAppConnectionOptionMap = { [AppConnection.Vercel]: TVercelConnectionOption; [AppConnection.Postgres]: TPostgresConnectionOption; [AppConnection.MsSql]: TMsSqlConnectionOption; + [AppConnection.MySql]: TMySqlConnectionOption; [AppConnection.Camunda]: TCamundaConnectionOption; [AppConnection.Windmill]: TWindmillConnectionOption; [AppConnection.Auth0]: TAuth0ConnectionOption; diff --git a/frontend/src/hooks/api/appConnections/types/index.ts b/frontend/src/hooks/api/appConnections/types/index.ts index 2b29c2cd4..aa69f0cc1 100644 --- a/frontend/src/hooks/api/appConnections/types/index.ts +++ b/frontend/src/hooks/api/appConnections/types/index.ts @@ -13,6 +13,7 @@ import { THCVaultConnection } from "./hc-vault-connection"; import { THumanitecConnection } from "./humanitec-connection"; import { TLdapConnection } from "./ldap-connection"; import { TMsSqlConnection } from "./mssql-connection"; +import { TMySqlConnection } from "./mysql-connection"; import { TOCIConnection } from "./oci-connection"; import { TPostgresConnection } from "./postgres-connection"; import { TTeamCityConnection } from "./teamcity-connection"; @@ -33,6 +34,7 @@ export * from "./hc-vault-connection"; export * from "./humanitec-connection"; export * from "./ldap-connection"; export * from "./mssql-connection"; +export * from "./mysql-connection"; export * from "./oci-connection"; export * from "./postgres-connection"; export * from "./teamcity-connection"; @@ -53,6 +55,7 @@ export type TAppConnection = | TVercelConnection | TPostgresConnection | TMsSqlConnection + | TMySqlConnection | TCamundaConnection | TWindmillConnection | TAuth0Connection @@ -99,6 +102,7 @@ export type TAppConnectionMap = { [AppConnection.Vercel]: TVercelConnection; [AppConnection.Postgres]: TPostgresConnection; [AppConnection.MsSql]: TMsSqlConnection; + [AppConnection.MySql]: TMySqlConnection; [AppConnection.Camunda]: TCamundaConnection; [AppConnection.Windmill]: TWindmillConnection; [AppConnection.Auth0]: TAuth0Connection; diff --git a/frontend/src/hooks/api/appConnections/types/mysql-connection.ts b/frontend/src/hooks/api/appConnections/types/mysql-connection.ts new file mode 100644 index 000000000..0b8ab67c6 --- /dev/null +++ b/frontend/src/hooks/api/appConnections/types/mysql-connection.ts @@ -0,0 +1,13 @@ +import { AppConnection } from "@app/hooks/api/appConnections/enums"; +import { TRootAppConnection } from "@app/hooks/api/appConnections/types/root-connection"; + +import { TBaseSqlConnectionCredentials } from "./shared"; + +export enum MySqlConnectionMethod { + UsernameAndPassword = "username-and-password" +} + +export type TMySqlConnection = TRootAppConnection & { app: AppConnection.MySql } & { + method: MySqlConnectionMethod.UsernameAndPassword; + credentials: TBaseSqlConnectionCredentials; +}; diff --git a/frontend/src/hooks/api/secretRotationsV2/enums.ts b/frontend/src/hooks/api/secretRotationsV2/enums.ts index 3b38c1d49..5daab0d9a 100644 --- a/frontend/src/hooks/api/secretRotationsV2/enums.ts +++ b/frontend/src/hooks/api/secretRotationsV2/enums.ts @@ -1,6 +1,7 @@ export enum SecretRotation { PostgresCredentials = "postgres-credentials", MsSqlCredentials = "mssql-credentials", + MySqlCredentials = "mysql-credentials", Auth0ClientSecret = "auth0-client-secret", AzureClientSecret = "azure-client-secret", LdapPassword = "ldap-password", diff --git a/frontend/src/hooks/api/secretRotationsV2/types/index.ts b/frontend/src/hooks/api/secretRotationsV2/types/index.ts index a1ef0bd15..6f1a82c68 100644 --- a/frontend/src/hooks/api/secretRotationsV2/types/index.ts +++ b/frontend/src/hooks/api/secretRotationsV2/types/index.ts @@ -31,9 +31,15 @@ import { TSqlCredentialsRotationOption } from "@app/hooks/api/secretRotationsV2/ import { SecretV3RawSanitized } from "@app/hooks/api/secrets/types"; import { DiscriminativePick } from "@app/types"; +import { + TMySqlCredentialsRotation, + TMySqlCredentialsRotationGeneratedCredentialsResponse +} from "./mysql-credentials-rotation"; + export type TSecretRotationV2 = ( | TPostgresCredentialsRotation | TMsSqlCredentialsRotation + | TMySqlCredentialsRotation | TAuth0ClientSecretRotation | TAzureClientSecretRotation | TLdapPasswordRotation @@ -56,6 +62,7 @@ export type TSecretRotationV2Response = { secretRotation: TSecretRotationV2 }; export type TViewSecretRotationGeneratedCredentialsResponse = | TPostgresCredentialsRotationGeneratedCredentialsResponse | TMsSqlCredentialsRotationGeneratedCredentialsResponse + | TMySqlCredentialsRotationGeneratedCredentialsResponse | TAuth0ClientSecretRotationGeneratedCredentialsResponse | TAzureClientSecretRotationGeneratedCredentialsResponse | TLdapPasswordRotationGeneratedCredentialsResponse @@ -105,6 +112,7 @@ export type TViewSecretRotationV2GeneratedCredentialsDTO = { export type TSecretRotationOptionMap = { [SecretRotation.PostgresCredentials]: TSqlCredentialsRotationOption; [SecretRotation.MsSqlCredentials]: TSqlCredentialsRotationOption; + [SecretRotation.MySqlCredentials]: TSqlCredentialsRotationOption; [SecretRotation.Auth0ClientSecret]: TAuth0ClientSecretRotationOption; [SecretRotation.AzureClientSecret]: TAzureClientSecretRotationOption; [SecretRotation.LdapPassword]: TLdapPasswordRotationOption; @@ -114,6 +122,7 @@ export type TSecretRotationOptionMap = { export type TSecretRotationGeneratedCredentialsResponseMap = { [SecretRotation.PostgresCredentials]: TPostgresCredentialsRotationGeneratedCredentialsResponse; [SecretRotation.MsSqlCredentials]: TMsSqlCredentialsRotationGeneratedCredentialsResponse; + [SecretRotation.MySqlCredentials]: TMySqlCredentialsRotationGeneratedCredentialsResponse; [SecretRotation.Auth0ClientSecret]: TAuth0ClientSecretRotationGeneratedCredentialsResponse; [SecretRotation.AzureClientSecret]: TAzureClientSecretRotationGeneratedCredentialsResponse; [SecretRotation.LdapPassword]: TLdapPasswordRotationGeneratedCredentialsResponse; diff --git a/frontend/src/hooks/api/secretRotationsV2/types/mysql-credentials-rotation.ts b/frontend/src/hooks/api/secretRotationsV2/types/mysql-credentials-rotation.ts new file mode 100644 index 000000000..0577a269c --- /dev/null +++ b/frontend/src/hooks/api/secretRotationsV2/types/mysql-credentials-rotation.ts @@ -0,0 +1,17 @@ +import { SecretRotation } from "@app/hooks/api/secretRotationsV2"; +import { + TSecretRotationV2Base, + TSecretRotationV2GeneratedCredentialsResponseBase, + TSqlCredentialsRotationGeneratedCredentials, + TSqlCredentialsRotationProperties +} from "@app/hooks/api/secretRotationsV2/types/shared"; + +export type TMySqlCredentialsRotation = TSecretRotationV2Base & { + type: SecretRotation.MySqlCredentials; +} & TSqlCredentialsRotationProperties; + +export type TMySqlCredentialsRotationGeneratedCredentialsResponse = + TSecretRotationV2GeneratedCredentialsResponseBase< + SecretRotation.MySqlCredentials, + TSqlCredentialsRotationGeneratedCredentials + >; diff --git a/frontend/src/hooks/api/secretRotationsV2/types/shared/sql-credentials-rotation.ts b/frontend/src/hooks/api/secretRotationsV2/types/shared/sql-credentials-rotation.ts index 1a212e9c9..3be6679f0 100644 --- a/frontend/src/hooks/api/secretRotationsV2/types/shared/sql-credentials-rotation.ts +++ b/frontend/src/hooks/api/secretRotationsV2/types/shared/sql-credentials-rotation.ts @@ -14,8 +14,11 @@ export type TSqlCredentialsRotationProperties = { export type TSqlCredentialsRotationOption = { name: string; - type: SecretRotation.PostgresCredentials | SecretRotation.MsSqlCredentials; - connection: AppConnection.Postgres | AppConnection.MsSql; + type: + | SecretRotation.PostgresCredentials + | SecretRotation.MsSqlCredentials + | SecretRotation.MySqlCredentials; + connection: AppConnection.Postgres | AppConnection.MsSql | AppConnection.MySql; template: { secretsMapping: TSqlCredentialsRotationProperties["secretsMapping"]; createUserStatement: 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 238dc4e04..c493421ce 100644 --- a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/AppConnectionForm.tsx +++ b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/AppConnectionForm.tsx @@ -22,6 +22,7 @@ import { HCVaultConnectionForm } from "./HCVaultConnectionForm"; import { HumanitecConnectionForm } from "./HumanitecConnectionForm"; import { LdapConnectionForm } from "./LdapConnectionForm"; import { MsSqlConnectionForm } from "./MsSqlConnectionForm"; +import { MySqlConnectionForm } from "./MySqlConnectionForm"; import { OCIConnectionForm } from "./OCIConnectionForm"; import { PostgresConnectionForm } from "./PostgresConnectionForm"; import { TeamCityConnectionForm } from "./TeamCityConnectionForm"; @@ -88,6 +89,8 @@ const CreateForm = ({ app, onComplete }: CreateFormProps) => { return ; case AppConnection.MsSql: return ; + case AppConnection.MySql: + return ; case AppConnection.Camunda: return ; case AppConnection.AzureClientSecrets: @@ -162,6 +165,8 @@ const UpdateForm = ({ appConnection, onComplete }: UpdateFormProps) => { return ; case AppConnection.MsSql: return ; + case AppConnection.MySql: + return ; case AppConnection.Camunda: return ; case AppConnection.AzureClientSecrets: diff --git a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/MySqlConnectionForm.tsx b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/MySqlConnectionForm.tsx new file mode 100644 index 000000000..c0022da55 --- /dev/null +++ b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/MySqlConnectionForm.tsx @@ -0,0 +1,155 @@ +import { useState } from "react"; +import { Controller, FormProvider, useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; + +import { Button, FormControl, ModalClose, Select, SelectItem } from "@app/components/v2"; +import { APP_CONNECTION_MAP, getAppConnectionMethodDetails } from "@app/helpers/appConnections"; +import { MySqlConnectionMethod, TMySqlConnection } from "@app/hooks/api/appConnections"; +import { AppConnection } from "@app/hooks/api/appConnections/enums"; +import { PlatformManagedConfirmationModal } from "@app/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/shared/PlatformManagedConfirmationModal"; + +import { + genericAppConnectionFieldsSchema, + GenericAppConnectionsFields +} from "./GenericAppConnectionFields"; +import { + BaseSqlUsernameAndPasswordConnectionSchema, + PlatformManagedNoticeBanner, + SqlConnectionFields +} from "./shared"; + +type Props = { + appConnection?: TMySqlConnection; + onSubmit: (formData: FormData) => Promise; +}; + +const rootSchema = genericAppConnectionFieldsSchema.extend({ + app: z.literal(AppConnection.MySql), + isPlatformManagedCredentials: z.boolean().optional() +}); + +const formSchema = z.discriminatedUnion("method", [ + rootSchema.extend({ + method: z.literal(MySqlConnectionMethod.UsernameAndPassword), + credentials: BaseSqlUsernameAndPasswordConnectionSchema + }) +]); + +type FormData = z.infer; + +export const MySqlConnectionForm = ({ appConnection, onSubmit }: Props) => { + const isUpdate = Boolean(appConnection); + const [showConfirmation, setShowConfirmation] = useState(false); + const [selectedTabIndex, setSelectedTabIndex] = useState(0); + + const form = useForm({ + resolver: zodResolver(formSchema), + defaultValues: appConnection ?? { + app: AppConnection.MySql, + method: MySqlConnectionMethod.UsernameAndPassword, + credentials: { + host: "", + port: 3306, + database: "default", + username: "", + password: "", + sslEnabled: true, + sslRejectUnauthorized: true, + sslCertificate: undefined + } + } + }); + + const { + handleSubmit, + control, + formState: { isSubmitting, isDirty } + } = form; + + const isPlatformManagedCredentials = appConnection?.isPlatformManagedCredentials ?? false; + + const confirmSubmit = async (formData: FormData) => { + if (formData.isPlatformManagedCredentials) { + setShowConfirmation(true); + return; + } + + await onSubmit(formData); + }; + + return ( + +
{ + setSelectedTabIndex(0); + handleSubmit(confirmSubmit)(e); + }} + > + {!isUpdate && } + ( + + + + )} + /> + + {isPlatformManagedCredentials ? ( + + ) : ( +
+ + + + +
+ )} + + handleSubmit(onSubmit)()} + onOpenChange={setShowConfirmation} + isOpen={showConfirmation} + /> +
+ ); +};