mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 04:27:29 +00:00
improvements: add ssl options to sql connections and update ui/docs
This commit is contained in:
+14
-1
@@ -7,7 +7,20 @@ export const MSSQL_CREDENTIALS_ROTATION_LIST_OPTION: TSecretRotationV2ListItem =
|
|||||||
type: SecretRotation.MsSqlCredentials,
|
type: SecretRotation.MsSqlCredentials,
|
||||||
connection: AppConnection.MsSql,
|
connection: AppConnection.MsSql,
|
||||||
template: {
|
template: {
|
||||||
createUserStatement: `CREATE LOGIN [my_mssql_user] WITH PASSWORD = 'my_temporary_password'; CREATE USER [my_mssql_user] FOR LOGIN [my_mssql_user]; GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO [my_mssql_user];`,
|
createUserStatement: `-- Create login at the server level
|
||||||
|
CREATE LOGIN [infisical_user] WITH PASSWORD = 'my-password';
|
||||||
|
|
||||||
|
-- Grant server-level connect permission
|
||||||
|
GRANT CONNECT SQL TO [infisical_user];
|
||||||
|
|
||||||
|
-- Switch to the database where you want to create the user
|
||||||
|
USE my_database;
|
||||||
|
|
||||||
|
-- Create the database user mapped to the login
|
||||||
|
CREATE USER [infisical_user] FOR LOGIN [infisical_user];
|
||||||
|
|
||||||
|
-- Grant permissions to the user on the schema in this database
|
||||||
|
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO [infisical_user];`,
|
||||||
secretsMapping: {
|
secretsMapping: {
|
||||||
username: "MSSQL_DB_USERNAME",
|
username: "MSSQL_DB_USERNAME",
|
||||||
password: "MSSQL_DB_PASSWORD"
|
password: "MSSQL_DB_PASSWORD"
|
||||||
|
|||||||
+8
-1
@@ -7,7 +7,14 @@ export const POSTGRES_CREDENTIALS_ROTATION_LIST_OPTION: TSecretRotationV2ListIte
|
|||||||
type: SecretRotation.PostgresCredentials,
|
type: SecretRotation.PostgresCredentials,
|
||||||
connection: AppConnection.Postgres,
|
connection: AppConnection.Postgres,
|
||||||
template: {
|
template: {
|
||||||
createUserStatement: `CREATE USER "my_pg_user" WITH ENCRYPTED PASSWORD 'temporary_password'; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "my_pg_user";`,
|
createUserStatement: `-- create user role
|
||||||
|
CREATE USER infisical_user WITH ENCRYPTED PASSWORD 'temporary_password';
|
||||||
|
|
||||||
|
-- grant database connection permissions
|
||||||
|
GRANT CONNECT ON DATABASE my_database TO infisical_user;
|
||||||
|
|
||||||
|
-- grant relevant table permissions
|
||||||
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO infisical_user;`,
|
||||||
secretsMapping: {
|
secretsMapping: {
|
||||||
username: "POSTGRES_DB_USERNAME",
|
username: "POSTGRES_DB_USERNAME",
|
||||||
password: "POSTGRES_DB_PASSWORD"
|
password: "POSTGRES_DB_PASSWORD"
|
||||||
|
|||||||
@@ -1691,6 +1691,8 @@ export const AppConnections = {
|
|||||||
database: "The name of the database to connect to.",
|
database: "The name of the database to connect to.",
|
||||||
username: "The username to connect to the database with.",
|
username: "The username to connect to the database with.",
|
||||||
password: "The password to connect to the database with.",
|
password: "The password to connect to the database with.",
|
||||||
|
sslEnabled: "Whether or not to use SSL when connecting to the database.",
|
||||||
|
sslRejectUnauthorized: "Whether or not to reject unauthorized SSL certificates.",
|
||||||
sslCertificate: "The SSL certificate to use for connection."
|
sslCertificate: "The SSL certificate to use for connection."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,8 +59,6 @@ const envSchema = z
|
|||||||
QUEUE_WORKERS_ENABLED: zodStrBool.default("true"),
|
QUEUE_WORKERS_ENABLED: zodStrBool.default("true"),
|
||||||
HTTPS_ENABLED: zodStrBool,
|
HTTPS_ENABLED: zodStrBool,
|
||||||
ROTATION_DEVELOPMENT_MODE: zodStrBool.default("false").optional(),
|
ROTATION_DEVELOPMENT_MODE: zodStrBool.default("false").optional(),
|
||||||
DB_SSL_REJECT_UNAUTHORIZED: zodStrBool.default("true"),
|
|
||||||
DB_SSL_REQUIRED: zodStrBool.default("true"),
|
|
||||||
// smtp options
|
// smtp options
|
||||||
SMTP_HOST: zpStr(z.string().optional()),
|
SMTP_HOST: zpStr(z.string().optional()),
|
||||||
SMTP_IGNORE_TLS: zodStrBool.default("false"),
|
SMTP_IGNORE_TLS: zodStrBool.default("false"),
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ export const SanitizedMsSqlConnectionSchema = z.discriminatedUnion("method", [
|
|||||||
host: true,
|
host: true,
|
||||||
database: true,
|
database: true,
|
||||||
port: true,
|
port: true,
|
||||||
username: true
|
username: true,
|
||||||
|
sslEnabled: true,
|
||||||
|
sslRejectUnauthorized: true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ export const SanitizedPostgresConnectionSchema = z.discriminatedUnion("method",
|
|||||||
host: true,
|
host: true,
|
||||||
database: true,
|
database: true,
|
||||||
port: true,
|
port: true,
|
||||||
username: true
|
username: true,
|
||||||
|
sslEnabled: true,
|
||||||
|
sslRejectUnauthorized: true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
TSqlCredentialsRotationGeneratedCredentials,
|
TSqlCredentialsRotationGeneratedCredentials,
|
||||||
TSqlCredentialsRotationWithConnection
|
TSqlCredentialsRotationWithConnection
|
||||||
} from "@app/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-types";
|
} from "@app/ee/services/secret-rotation-v2/shared/sql-credentials/sql-credentials-rotation-types";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
|
||||||
import { BadRequestError, DatabaseError } from "@app/lib/errors";
|
import { BadRequestError, DatabaseError } from "@app/lib/errors";
|
||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
@@ -21,16 +20,14 @@ const SQL_CONNECTION_CLIENT_MAP = {
|
|||||||
|
|
||||||
const getConnectionConfig = ({
|
const getConnectionConfig = ({
|
||||||
app,
|
app,
|
||||||
credentials: { sslCertificate, host }
|
credentials: { host, sslCertificate, sslEnabled, sslRejectUnauthorized }
|
||||||
}: Pick<TSqlConnection, "credentials" | "app">) => {
|
}: Pick<TSqlConnection, "credentials" | "app">) => {
|
||||||
const appCfg = getConfig();
|
|
||||||
|
|
||||||
switch (app) {
|
switch (app) {
|
||||||
case AppConnection.Postgres: {
|
case AppConnection.Postgres: {
|
||||||
return {
|
return {
|
||||||
ssl: appCfg.DB_SSL_REQUIRED
|
ssl: sslEnabled
|
||||||
? {
|
? {
|
||||||
rejectUnauthorized: appCfg.DB_SSL_REJECT_UNAUTHORIZED,
|
rejectUnauthorized: sslRejectUnauthorized,
|
||||||
ca: sslCertificate,
|
ca: sslCertificate,
|
||||||
servername: host
|
servername: host
|
||||||
}
|
}
|
||||||
@@ -39,13 +36,13 @@ const getConnectionConfig = ({
|
|||||||
}
|
}
|
||||||
case AppConnection.MsSql: {
|
case AppConnection.MsSql: {
|
||||||
return {
|
return {
|
||||||
options: appCfg.DB_SSL_REQUIRED
|
options: sslEnabled
|
||||||
? {
|
? {
|
||||||
trustServerCertificate: !appCfg.DB_SSL_REJECT_UNAUTHORIZED,
|
trustServerCertificate: !sslRejectUnauthorized,
|
||||||
encrypt: true,
|
encrypt: true,
|
||||||
cryptoCredentialsDetails: sslCertificate ? { ca: sslCertificate } : {}
|
cryptoCredentialsDetails: sslCertificate ? { ca: sslCertificate } : {}
|
||||||
}
|
}
|
||||||
: undefined
|
: { encrypt: false }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -8,5 +8,12 @@ export const BaseSqlUsernameAndPasswordConnectionSchema = z.object({
|
|||||||
database: z.string().trim().min(1, "Database required").describe(AppConnections.CREDENTIALS.SQL_CONNECTION.database),
|
database: z.string().trim().min(1, "Database required").describe(AppConnections.CREDENTIALS.SQL_CONNECTION.database),
|
||||||
username: z.string().trim().min(1, "Username required").describe(AppConnections.CREDENTIALS.SQL_CONNECTION.username),
|
username: z.string().trim().min(1, "Username required").describe(AppConnections.CREDENTIALS.SQL_CONNECTION.username),
|
||||||
password: z.string().trim().min(1, "Password required").describe(AppConnections.CREDENTIALS.SQL_CONNECTION.password),
|
password: z.string().trim().min(1, "Password required").describe(AppConnections.CREDENTIALS.SQL_CONNECTION.password),
|
||||||
sslCertificate: z.string().trim().optional().describe(AppConnections.CREDENTIALS.SQL_CONNECTION.sslCertificate)
|
sslEnabled: z.boolean().describe(AppConnections.CREDENTIALS.SQL_CONNECTION.sslEnabled),
|
||||||
|
sslRejectUnauthorized: z.boolean().describe(AppConnections.CREDENTIALS.SQL_CONNECTION.sslRejectUnauthorized),
|
||||||
|
sslCertificate: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.transform((value) => value || undefined)
|
||||||
|
.optional()
|
||||||
|
.describe(AppConnections.CREDENTIALS.SQL_CONNECTION.sslCertificate)
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,19 +11,19 @@ description: "Learn how to automatically rotate Microsoft SQL Server credentials
|
|||||||
An example creation statement might look like:
|
An example creation statement might look like:
|
||||||
```SQL
|
```SQL
|
||||||
-- create server-level logins
|
-- create server-level logins
|
||||||
CREATE LOGIN infisical_user_1 WITH PASSWORD = 'my-password';
|
CREATE LOGIN [infisical_user_1] WITH PASSWORD = 'my-password';
|
||||||
CREATE LOGIN infisical_user_2 WITH PASSWORD = 'my-password';
|
CREATE LOGIN [infisical_user_2] WITH PASSWORD = 'my-password';
|
||||||
|
GRANT CONNECT SQL TO [infisical_user_1];
|
||||||
|
GRANT CONNECT SQL TO [infisical_user_2];
|
||||||
|
|
||||||
-- create database-level users with login from above
|
-- create database-level users with login from above
|
||||||
USE my_database;
|
USE my_database;
|
||||||
CREATE USER infisical_user_1 FOR LOGIN infisical_user_1;
|
CREATE USER [infisical_user_1] FOR LOGIN [infisical_user_1];
|
||||||
CREATE USER infisical_user_2 FOR LOGIN infisical_user_2;
|
CREATE USER [infisical_user_2] FOR LOGIN [infisical_user_2];
|
||||||
GRANT CONNECT TO infisical_user_1;
|
|
||||||
GRANT CONNECT TO infisical_user_2;
|
|
||||||
|
|
||||||
-- grant relevant permissions
|
-- grant relevant permissions
|
||||||
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO infisical_user_1;
|
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO [infisical_user_1];
|
||||||
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO infisical_user_2;
|
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO [infisical_user_2];
|
||||||
```
|
```
|
||||||
|
|
||||||
<Tip>
|
<Tip>
|
||||||
|
|||||||
@@ -10,14 +10,16 @@ description: "Learn how to automatically rotate PostgreSQL credentials."
|
|||||||
|
|
||||||
An example creation statement might look like:
|
An example creation statement might look like:
|
||||||
```SQL
|
```SQL
|
||||||
-- first user
|
-- create user roles
|
||||||
CREATE USER infisical_user_1 WITH ENCRYPTED PASSWORD 'temporary_password';
|
CREATE USER infisical_user_1 WITH ENCRYPTED PASSWORD 'temporary_password';
|
||||||
GRANT CONNECT ON DATABASE my_database TO infisical_user_1;
|
|
||||||
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO infisical_user_1;
|
|
||||||
|
|
||||||
-- second user
|
|
||||||
CREATE USER infisical_user_2 WITH ENCRYPTED PASSWORD 'temporary_password';
|
CREATE USER infisical_user_2 WITH ENCRYPTED PASSWORD 'temporary_password';
|
||||||
|
|
||||||
|
-- grant database connection permissions
|
||||||
|
GRANT CONNECT ON DATABASE my_database TO infisical_user_1;
|
||||||
GRANT CONNECT ON DATABASE my_database TO infisical_user_2;
|
GRANT CONNECT ON DATABASE my_database TO infisical_user_2;
|
||||||
|
|
||||||
|
-- grant relevant table permissions
|
||||||
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO infisical_user_1;
|
||||||
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO infisical_user_2;
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO infisical_user_2;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 792 KiB After Width: | Height: | Size: 826 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 790 KiB After Width: | Height: | Size: 825 KiB |
@@ -11,16 +11,20 @@ Infisical supports connecting to Microsoft SQL Server using database principals.
|
|||||||
<Step title="Create a Principal">
|
<Step title="Create a Principal">
|
||||||
Infisical recommends creating a designated server login and database user in your Microsoft SQL Server database for your connection.
|
Infisical recommends creating a designated server login and database user in your Microsoft SQL Server database for your connection.
|
||||||
```SQL
|
```SQL
|
||||||
-- create server-level login
|
-- Create login at the server level
|
||||||
CREATE LOGIN infisical_login WITH PASSWORD = 'my-password';
|
CREATE LOGIN [infisical_app] WITH PASSWORD = 'my-password';
|
||||||
|
|
||||||
-- create database-level user with login from above
|
-- Grant server-level connect permission
|
||||||
|
GRANT CONNECT SQL TO [infisical_app];
|
||||||
|
|
||||||
|
-- Switch to the specific database where you want to create the user
|
||||||
USE my_database;
|
USE my_database;
|
||||||
CREATE USER infisical_user FOR LOGIN infisical_login;
|
|
||||||
GRANT CONNECT TO infisical_user;
|
-- Create the database user mapped to the login
|
||||||
|
CREATE USER [infisical_app] FOR LOGIN [infisical_app];
|
||||||
|
|
||||||
-- If you intend to use Platform Managed Credentials (see below)
|
-- If you intend to use Platform Managed Credentials (see below)
|
||||||
GRANT ALTER ANY LOGIN TO infisical_login;
|
GRANT ALTER ANY LOGIN TO [infisical_app];
|
||||||
```
|
```
|
||||||
</Step>
|
</Step>
|
||||||
<Step title="Grant Relevant Permissions">
|
<Step title="Grant Relevant Permissions">
|
||||||
@@ -95,6 +99,8 @@ Infisical supports connecting to Microsoft SQL Server using database principals.
|
|||||||
"database": "default",
|
"database": "default",
|
||||||
"username": "infisical_login",
|
"username": "infisical_login",
|
||||||
"password": "my-password",
|
"password": "my-password",
|
||||||
|
"sslEnabled": true,
|
||||||
|
"sslRejectUnauthorized": true
|
||||||
},
|
},
|
||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
@@ -117,7 +123,9 @@ Infisical supports connecting to Microsoft SQL Server using database principals.
|
|||||||
"host": "123.4.5.6",
|
"host": "123.4.5.6",
|
||||||
"port": 1433,
|
"port": 1433,
|
||||||
"database": "default",
|
"database": "default",
|
||||||
"username": "infisical_login"
|
"username": "infisical_login",
|
||||||
|
"sslEnabled": true,
|
||||||
|
"sslRejectUnauthorized": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Infisical supports connecting to PostgreSQL using a database role.
|
|||||||
Infisical recommends creating a designated role in your PostgreSQL database for your connection.
|
Infisical recommends creating a designated role in your PostgreSQL database for your connection.
|
||||||
```SQL
|
```SQL
|
||||||
-- create user role
|
-- create user role
|
||||||
CREATE ROLE infisical_role WITH LOGIN PASSWORD 'my-password'
|
CREATE ROLE infisical_role WITH LOGIN PASSWORD 'my-password';
|
||||||
|
|
||||||
-- grant login access to the specified database
|
-- grant login access to the specified database
|
||||||
GRANT CONNECT ON DATABASE my_database TO infisical_role;
|
GRANT CONNECT ON DATABASE my_database TO infisical_role;
|
||||||
@@ -27,6 +27,7 @@ Infisical supports connecting to PostgreSQL using a database role.
|
|||||||
<Tab title="Secret Rotation">
|
<Tab title="Secret Rotation">
|
||||||
For Secret Rotations, your Infisical user will require the ability to alter other users' passwords:
|
For Secret Rotations, your Infisical user will require the ability to alter other users' passwords:
|
||||||
```SQL
|
```SQL
|
||||||
|
-- enable permissions to alter login credentials
|
||||||
ALTER ROLE infisical_role WITH CREATEROLE;
|
ALTER ROLE infisical_role WITH CREATEROLE;
|
||||||
```
|
```
|
||||||
</Tab>
|
</Tab>
|
||||||
@@ -88,6 +89,8 @@ Infisical supports connecting to PostgreSQL using a database role.
|
|||||||
"database": "default",
|
"database": "default",
|
||||||
"username": "infisical_role",
|
"username": "infisical_role",
|
||||||
"password": "my-password",
|
"password": "my-password",
|
||||||
|
"sslEnabled": true,
|
||||||
|
"sslRejectUnauthorized": true
|
||||||
},
|
},
|
||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
@@ -110,7 +113,9 @@ Infisical supports connecting to PostgreSQL using a database role.
|
|||||||
"host": "123.4.5.6",
|
"host": "123.4.5.6",
|
||||||
"port": 5432,
|
"port": 5432,
|
||||||
"database": "default",
|
"database": "default",
|
||||||
"username": "infisical_role"
|
"username": "infisical_role",
|
||||||
|
"sslEnabled": true,
|
||||||
|
"sslRejectUnauthorized": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -439,19 +439,6 @@ When set, all visits to the Infisical login page will automatically redirect use
|
|||||||
information.
|
information.
|
||||||
</Accordion>
|
</Accordion>
|
||||||
|
|
||||||
## External Database Connections
|
|
||||||
|
|
||||||
<ParamField query="DB_SSL_REJECT_UNAUTHORIZED" type="boolean" default="true" optional>
|
|
||||||
Specify whether external database connections should reject unauthorized SSL certificates.
|
|
||||||
We highly recommend keeping this value set to `true` for production use-cases.
|
|
||||||
</ParamField>
|
|
||||||
|
|
||||||
<ParamField query="DB_SSL_REQUIRED" type="boolean" default="true" optional>
|
|
||||||
Specify whether external database connections should require SSL.
|
|
||||||
We highly recommend keeping this value set to `true` for production use-cases.
|
|
||||||
</ParamField>
|
|
||||||
|
|
||||||
|
|
||||||
## App Connections
|
## App Connections
|
||||||
|
|
||||||
You can configure third-party app connections for re-use across Infisical Projects.
|
You can configure third-party app connections for re-use across Infisical Projects.
|
||||||
|
|||||||
+1
-1
@@ -57,7 +57,7 @@ export const SqlRotationParametersFields = () => {
|
|||||||
to suit your needs.
|
to suit your needs.
|
||||||
</p>
|
</p>
|
||||||
<p className="mb-3 text-sm">
|
<p className="mb-3 text-sm">
|
||||||
<pre className="whitespace-pre-wrap rounded border border-mineshaft-700 bg-mineshaft-800 p-2 text-mineshaft-300">
|
<pre className="max-h-[10rem] overflow-y-auto whitespace-pre-wrap rounded border border-mineshaft-700 bg-mineshaft-800 p-2 text-mineshaft-300">
|
||||||
{rotationOption!.template.createUserStatement}
|
{rotationOption!.template.createUserStatement}
|
||||||
</pre>
|
</pre>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -4,4 +4,6 @@ export type TBaseSqlConnectionCredentials = {
|
|||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
database: string;
|
database: string;
|
||||||
|
sslEnabled: boolean;
|
||||||
|
sslRejectUnauthorized: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ import {
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
appConnection?: TAwsConnection;
|
appConnection?: TAwsConnection;
|
||||||
onSubmit: (formData: FormData) => void;
|
onSubmit: (formData: FormData) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@ import {
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
appConnection?: TDatabricksConnection;
|
appConnection?: TDatabricksConnection;
|
||||||
onSubmit: (formData: FormData) => void;
|
onSubmit: (formData: FormData) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ import {
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
appConnection?: TGcpConnection;
|
appConnection?: TGcpConnection;
|
||||||
onSubmit: (formData: FormData) => void;
|
onSubmit: (formData: FormData) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ import {
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
appConnection?: THumanitecConnection;
|
appConnection?: THumanitecConnection;
|
||||||
onSubmit: (formData: FormData) => void;
|
onSubmit: (formData: FormData) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
||||||
|
|||||||
+18
-6
@@ -24,7 +24,7 @@ import {
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
appConnection?: TMsSqlConnection;
|
appConnection?: TMsSqlConnection;
|
||||||
onSubmit: (formData: FormData) => void;
|
onSubmit: (formData: FormData) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
||||||
@@ -44,6 +44,7 @@ type FormData = z.infer<typeof formSchema>;
|
|||||||
export const MsSqlConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
export const MsSqlConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
||||||
const isUpdate = Boolean(appConnection);
|
const isUpdate = Boolean(appConnection);
|
||||||
const [showConfirmation, setShowConfirmation] = useState(false);
|
const [showConfirmation, setShowConfirmation] = useState(false);
|
||||||
|
const [selectedTabIndex, setSelectedTabIndex] = useState(0);
|
||||||
|
|
||||||
const form = useForm<FormData>({
|
const form = useForm<FormData>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
@@ -56,7 +57,9 @@ export const MsSqlConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
|||||||
database: "default",
|
database: "default",
|
||||||
username: "",
|
username: "",
|
||||||
password: "",
|
password: "",
|
||||||
sslCertificate: ""
|
sslEnabled: true,
|
||||||
|
sslRejectUnauthorized: true,
|
||||||
|
sslCertificate: undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -69,18 +72,23 @@ export const MsSqlConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
|||||||
|
|
||||||
const isPlatformManagedCredentials = appConnection?.isPlatformManagedCredentials ?? false;
|
const isPlatformManagedCredentials = appConnection?.isPlatformManagedCredentials ?? false;
|
||||||
|
|
||||||
const confirmSubmit = (formData: FormData) => {
|
const confirmSubmit = async (formData: FormData) => {
|
||||||
if (formData.isPlatformManagedCredentials) {
|
if (formData.isPlatformManagedCredentials) {
|
||||||
setShowConfirmation(true);
|
setShowConfirmation(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit(formData);
|
await onSubmit(formData);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<form onSubmit={handleSubmit(confirmSubmit)}>
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
setSelectedTabIndex(0);
|
||||||
|
handleSubmit(confirmSubmit)(e);
|
||||||
|
}}
|
||||||
|
>
|
||||||
{!isUpdate && <GenericAppConnectionsFields />}
|
{!isUpdate && <GenericAppConnectionsFields />}
|
||||||
<Controller
|
<Controller
|
||||||
name="method"
|
name="method"
|
||||||
@@ -113,7 +121,11 @@ export const MsSqlConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<SqlConnectionFields isPlatformManagedCredentials={isPlatformManagedCredentials} />
|
<SqlConnectionFields
|
||||||
|
isPlatformManagedCredentials={isPlatformManagedCredentials}
|
||||||
|
selectedTabIndex={selectedTabIndex}
|
||||||
|
setSelectedTabIndex={setSelectedTabIndex}
|
||||||
|
/>
|
||||||
{isPlatformManagedCredentials ? (
|
{isPlatformManagedCredentials ? (
|
||||||
<PlatformManagedNoticeBanner />
|
<PlatformManagedNoticeBanner />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
+18
-6
@@ -21,7 +21,7 @@ import {
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
appConnection?: TPostgresConnection;
|
appConnection?: TPostgresConnection;
|
||||||
onSubmit: (formData: FormData) => void;
|
onSubmit: (formData: FormData) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
const rootSchema = genericAppConnectionFieldsSchema.extend({
|
||||||
@@ -41,6 +41,7 @@ type FormData = z.infer<typeof formSchema>;
|
|||||||
export const PostgresConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
export const PostgresConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
||||||
const isUpdate = Boolean(appConnection);
|
const isUpdate = Boolean(appConnection);
|
||||||
const [showConfirmation, setShowConfirmation] = useState(false);
|
const [showConfirmation, setShowConfirmation] = useState(false);
|
||||||
|
const [selectedTabIndex, setSelectedTabIndex] = useState(0);
|
||||||
|
|
||||||
const form = useForm<FormData>({
|
const form = useForm<FormData>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
@@ -53,7 +54,9 @@ export const PostgresConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
|||||||
database: "default",
|
database: "default",
|
||||||
username: "",
|
username: "",
|
||||||
password: "",
|
password: "",
|
||||||
sslCertificate: ""
|
sslEnabled: true,
|
||||||
|
sslRejectUnauthorized: true,
|
||||||
|
sslCertificate: undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -66,18 +69,23 @@ export const PostgresConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
|||||||
|
|
||||||
const isPlatformManagedCredentials = appConnection?.isPlatformManagedCredentials ?? false;
|
const isPlatformManagedCredentials = appConnection?.isPlatformManagedCredentials ?? false;
|
||||||
|
|
||||||
const confirmSubmit = (formData: FormData) => {
|
const confirmSubmit = async (formData: FormData) => {
|
||||||
if (formData.isPlatformManagedCredentials) {
|
if (formData.isPlatformManagedCredentials) {
|
||||||
setShowConfirmation(true);
|
setShowConfirmation(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit(formData);
|
await onSubmit(formData);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormProvider {...form}>
|
<FormProvider {...form}>
|
||||||
<form onSubmit={handleSubmit(confirmSubmit)}>
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
setSelectedTabIndex(0);
|
||||||
|
handleSubmit(confirmSubmit)(e);
|
||||||
|
}}
|
||||||
|
>
|
||||||
{!isUpdate && <GenericAppConnectionsFields />}
|
{!isUpdate && <GenericAppConnectionsFields />}
|
||||||
<Controller
|
<Controller
|
||||||
name="method"
|
name="method"
|
||||||
@@ -110,7 +118,11 @@ export const PostgresConnectionForm = ({ appConnection, onSubmit }: Props) => {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<SqlConnectionFields isPlatformManagedCredentials={isPlatformManagedCredentials} />
|
<SqlConnectionFields
|
||||||
|
isPlatformManagedCredentials={isPlatformManagedCredentials}
|
||||||
|
selectedTabIndex={selectedTabIndex}
|
||||||
|
setSelectedTabIndex={setSelectedTabIndex}
|
||||||
|
/>
|
||||||
{isPlatformManagedCredentials ? (
|
{isPlatformManagedCredentials ? (
|
||||||
<PlatformManagedNoticeBanner />
|
<PlatformManagedNoticeBanner />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
+189
-104
@@ -1,122 +1,207 @@
|
|||||||
|
import { Dispatch, SetStateAction } from "react";
|
||||||
import { Controller, useFormContext } from "react-hook-form";
|
import { Controller, useFormContext } from "react-hook-form";
|
||||||
import { faQuestionCircle } from "@fortawesome/free-solid-svg-icons";
|
import { faQuestionCircle } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { Tab } from "@headlessui/react";
|
||||||
|
|
||||||
import { FormControl, Input, SecretInput, Switch, TextArea, Tooltip } from "@app/components/v2";
|
import { FormControl, Input, SecretInput, Switch, TextArea, Tooltip } from "@app/components/v2";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isPlatformManagedCredentials: boolean;
|
isPlatformManagedCredentials: boolean;
|
||||||
|
selectedTabIndex: number;
|
||||||
|
setSelectedTabIndex: Dispatch<SetStateAction<number>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SqlConnectionFields = ({ isPlatformManagedCredentials }: Props) => {
|
export const SqlConnectionFields = ({
|
||||||
const { control } = useFormContext();
|
isPlatformManagedCredentials,
|
||||||
|
setSelectedTabIndex,
|
||||||
|
selectedTabIndex
|
||||||
|
}: Props) => {
|
||||||
|
const { control, watch } = useFormContext();
|
||||||
|
|
||||||
|
const sslEnabled = watch("credentials.sslEnabled");
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex items-start gap-2">
|
<Tab.Group selectedIndex={selectedTabIndex} onChange={setSelectedTabIndex}>
|
||||||
<Controller
|
<Tab.List className="-pb-1 mb-6 w-full border-b-2 border-mineshaft-600">
|
||||||
name="credentials.host"
|
<Tab
|
||||||
control={control}
|
className={({ selected }) =>
|
||||||
shouldUnregister
|
`w-30 -mb-[0.14rem] px-4 py-2 text-sm font-medium outline-none disabled:opacity-60 ${
|
||||||
render={({ field, fieldState: { error } }) => (
|
selected ? "border-b-2 border-mineshaft-300 text-mineshaft-200" : "text-bunker-300"
|
||||||
<FormControl
|
}`
|
||||||
className="flex-1"
|
}
|
||||||
errorText={error?.message}
|
|
||||||
isError={Boolean(error?.message)}
|
|
||||||
label="Host"
|
|
||||||
>
|
|
||||||
<Input {...field} isDisabled={isPlatformManagedCredentials} />
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
name="credentials.database"
|
|
||||||
control={control}
|
|
||||||
shouldUnregister
|
|
||||||
render={({ field, fieldState: { error } }) => (
|
|
||||||
<FormControl
|
|
||||||
className="flex-1"
|
|
||||||
errorText={error?.message}
|
|
||||||
isError={Boolean(error?.message)}
|
|
||||||
label="Database Name"
|
|
||||||
>
|
|
||||||
<Input {...field} isDisabled={isPlatformManagedCredentials} />
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
name="credentials.port"
|
|
||||||
control={control}
|
|
||||||
shouldUnregister
|
|
||||||
render={({ field, fieldState: { error } }) => (
|
|
||||||
<FormControl
|
|
||||||
className="w-28"
|
|
||||||
errorText={error?.message}
|
|
||||||
isError={Boolean(error?.message)}
|
|
||||||
label="Port"
|
|
||||||
>
|
|
||||||
<Input type="number" {...field} isDisabled={isPlatformManagedCredentials} />
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-start gap-2">
|
|
||||||
<Controller
|
|
||||||
name="credentials.username"
|
|
||||||
control={control}
|
|
||||||
shouldUnregister
|
|
||||||
render={({ field, fieldState: { error } }) => (
|
|
||||||
<FormControl
|
|
||||||
errorText={error?.message}
|
|
||||||
isError={Boolean(error?.message)}
|
|
||||||
label="Username"
|
|
||||||
className="flex-1"
|
|
||||||
>
|
|
||||||
<Input {...field} isDisabled={isPlatformManagedCredentials} />
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
name="credentials.password"
|
|
||||||
control={control}
|
|
||||||
shouldUnregister
|
|
||||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
|
||||||
<FormControl
|
|
||||||
errorText={error?.message}
|
|
||||||
isError={Boolean(error?.message)}
|
|
||||||
label="Password"
|
|
||||||
className="flex-1"
|
|
||||||
>
|
|
||||||
<SecretInput
|
|
||||||
containerClassName="text-gray-400 w-full group-focus-within:!border-primary-400/50 border border-mineshaft-500 bg-mineshaft-900 px-2.5 py-1.5"
|
|
||||||
value={value}
|
|
||||||
onChange={(e) => onChange(e.target.value)}
|
|
||||||
isDisabled={isPlatformManagedCredentials}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Controller
|
|
||||||
name="credentials.sslCertificate"
|
|
||||||
control={control}
|
|
||||||
shouldUnregister
|
|
||||||
render={({ field, fieldState: { error } }) => (
|
|
||||||
<FormControl
|
|
||||||
errorText={error?.message}
|
|
||||||
isError={Boolean(error?.message)}
|
|
||||||
label="SSL Certificate"
|
|
||||||
isOptional
|
|
||||||
>
|
>
|
||||||
<TextArea
|
Configuration
|
||||||
className="!resize-none"
|
</Tab>
|
||||||
rows={1}
|
<Tab
|
||||||
{...field}
|
className={({ selected }) =>
|
||||||
isDisabled={isPlatformManagedCredentials}
|
`w-30 -mb-[0.14rem] px-4 py-2 text-sm font-medium outline-none disabled:opacity-60 ${
|
||||||
|
selected ? "border-b-2 border-mineshaft-300 text-mineshaft-200" : "text-bunker-300"
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
>
|
||||||
|
SSL ({sslEnabled ? "Enabled" : "Disabled"})
|
||||||
|
</Tab>
|
||||||
|
</Tab.List>
|
||||||
|
<Tab.Panels className="mb-4 rounded border border-mineshaft-600 bg-mineshaft-700/70 p-3 pb-0">
|
||||||
|
<Tab.Panel>
|
||||||
|
<div className="mt-[0.675rem] flex items-start gap-2">
|
||||||
|
<Controller
|
||||||
|
name="credentials.host"
|
||||||
|
control={control}
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
className="flex-1"
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
label="Host"
|
||||||
|
>
|
||||||
|
<Input {...field} isDisabled={isPlatformManagedCredentials} />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
name="credentials.database"
|
||||||
|
control={control}
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
className="flex-1"
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
label="Database Name"
|
||||||
|
>
|
||||||
|
<Input {...field} isDisabled={isPlatformManagedCredentials} />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
name="credentials.port"
|
||||||
|
control={control}
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
className="w-28"
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
label="Port"
|
||||||
|
>
|
||||||
|
<Input type="number" {...field} isDisabled={isPlatformManagedCredentials} />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-[0.675rem] flex items-start gap-2">
|
||||||
|
<Controller
|
||||||
|
name="credentials.username"
|
||||||
|
control={control}
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
label="Username"
|
||||||
|
className="flex-1"
|
||||||
|
>
|
||||||
|
<Input {...field} isDisabled={isPlatformManagedCredentials} />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
name="credentials.password"
|
||||||
|
control={control}
|
||||||
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
label="Password"
|
||||||
|
className="flex-1"
|
||||||
|
>
|
||||||
|
<SecretInput
|
||||||
|
containerClassName="text-gray-400 w-full group-focus-within:!border-primary-400/50 border border-mineshaft-500 bg-mineshaft-900 px-2.5 py-1.5"
|
||||||
|
value={value}
|
||||||
|
onChange={(e) => onChange(e.target.value)}
|
||||||
|
isDisabled={isPlatformManagedCredentials}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Tab.Panel>
|
||||||
|
<Tab.Panel>
|
||||||
|
<Controller
|
||||||
|
name="credentials.sslEnabled"
|
||||||
|
control={control}
|
||||||
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
|
<FormControl isError={Boolean(error?.message)} errorText={error?.message}>
|
||||||
|
<Switch
|
||||||
|
className="bg-mineshaft-400/50 shadow-inner data-[state=checked]:bg-green/80"
|
||||||
|
id="platform-managed"
|
||||||
|
thumbClassName="bg-mineshaft-800"
|
||||||
|
isChecked={value}
|
||||||
|
onCheckedChange={onChange}
|
||||||
|
isDisabled={isPlatformManagedCredentials}
|
||||||
|
>
|
||||||
|
Enable SSL
|
||||||
|
</Switch>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
|
||||||
)}
|
<Controller
|
||||||
/>
|
name="credentials.sslCertificate"
|
||||||
|
control={control}
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
className={sslEnabled ? "" : "opacity-50"}
|
||||||
|
label="SSL Certificate"
|
||||||
|
isOptional
|
||||||
|
>
|
||||||
|
<TextArea
|
||||||
|
className="h-[3.5rem] !resize-none"
|
||||||
|
{...field}
|
||||||
|
isDisabled={isPlatformManagedCredentials || !sslEnabled}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
name="credentials.sslRejectUnauthorized"
|
||||||
|
control={control}
|
||||||
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
className={sslEnabled ? "" : "opacity-50"}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
className="bg-mineshaft-400/50 shadow-inner data-[state=checked]:bg-green/80"
|
||||||
|
id="platform-managed"
|
||||||
|
thumbClassName="bg-mineshaft-800"
|
||||||
|
isChecked={sslEnabled ? value : false}
|
||||||
|
onCheckedChange={onChange}
|
||||||
|
isDisabled={isPlatformManagedCredentials || !sslEnabled}
|
||||||
|
>
|
||||||
|
<p className="w-[9.5rem]">
|
||||||
|
Reject Unauthorized
|
||||||
|
<Tooltip
|
||||||
|
className="max-w-md"
|
||||||
|
content={
|
||||||
|
<p>
|
||||||
|
If enabled, Infisical will only connect to servers that have valid,
|
||||||
|
trusted SSL certificates.
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faQuestionCircle} size="sm" className="ml-1" />
|
||||||
|
</Tooltip>
|
||||||
|
</p>
|
||||||
|
</Switch>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Tab.Panel>
|
||||||
|
</Tab.Panels>
|
||||||
|
</Tab.Group>
|
||||||
{!isPlatformManagedCredentials && (
|
{!isPlatformManagedCredentials && (
|
||||||
<Controller
|
<Controller
|
||||||
name="isPlatformManagedCredentials"
|
name="isPlatformManagedCredentials"
|
||||||
|
|||||||
+7
-1
@@ -6,5 +6,11 @@ export const BaseSqlUsernameAndPasswordConnectionSchema = z.object({
|
|||||||
database: z.string().trim().min(1, "Database required").default("default"),
|
database: z.string().trim().min(1, "Database required").default("default"),
|
||||||
username: z.string().trim().min(1, "Username required"),
|
username: z.string().trim().min(1, "Username required"),
|
||||||
password: z.string().trim().min(1, "Password required"),
|
password: z.string().trim().min(1, "Password required"),
|
||||||
sslCertificate: z.string().trim().optional()
|
sslEnabled: z.boolean().default(true),
|
||||||
|
sslRejectUnauthorized: z.boolean().default(true),
|
||||||
|
sslCertificate: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.transform((value) => value || undefined)
|
||||||
|
.optional()
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user