mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 18:27:36 +00:00
fix(server): resolved failing to use dynamic secret due to superuser
This commit is contained in:
+11
-1
@@ -90,7 +90,17 @@ export const secretRotationDbFn = async ({
|
|||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
const ssl = ca ? { rejectUnauthorized: false, ca } : undefined;
|
const ssl = ca ? { rejectUnauthorized: false, ca } : undefined;
|
||||||
if (host === "localhost" || host === "127.0.0.1" || getDbConnectionHost(appCfg.DB_CONNECTION_URI) === host)
|
const dbHost = appCfg.DB_HOST || getDbConnectionHost(appCfg.DB_CONNECTION_URI);
|
||||||
|
if (
|
||||||
|
host === "localhost" ||
|
||||||
|
host === "127.0.0.1" ||
|
||||||
|
// database infisical uses
|
||||||
|
dbHost === host ||
|
||||||
|
// internal ips
|
||||||
|
host === "host.docker.internal" ||
|
||||||
|
host.match(/^10\.\d+\.\d+\.\d+/) ||
|
||||||
|
host.match(/^192\.168\.\d+\.\d+/)
|
||||||
|
)
|
||||||
throw new Error("Invalid db host");
|
throw new Error("Invalid db host");
|
||||||
|
|
||||||
const db = knex({
|
const db = knex({
|
||||||
|
|||||||
@@ -23,7 +23,17 @@ export const SqlDatabaseProvider = (): TDynamicProviderFns => {
|
|||||||
const dbHost = appCfg.DB_HOST || getDbConnectionHost(appCfg.DB_CONNECTION_URI);
|
const dbHost = appCfg.DB_HOST || getDbConnectionHost(appCfg.DB_CONNECTION_URI);
|
||||||
|
|
||||||
const providerInputs = await DynamicSecretSqlDBSchema.parseAsync(inputs);
|
const providerInputs = await DynamicSecretSqlDBSchema.parseAsync(inputs);
|
||||||
if (providerInputs.host === "localhost" || providerInputs.host === "127.0.0.1" || dbHost === providerInputs.host)
|
if (
|
||||||
|
// localhost
|
||||||
|
providerInputs.host === "localhost" ||
|
||||||
|
providerInputs.host === "127.0.0.1" ||
|
||||||
|
// database infisical uses
|
||||||
|
dbHost === providerInputs.host ||
|
||||||
|
// internal ips
|
||||||
|
providerInputs.host === "host.docker.internal" ||
|
||||||
|
providerInputs.host.match(/^10\.\d+\.\d+\.\d+/) ||
|
||||||
|
providerInputs.host.match(/^192\.168\.\d+\.\d+/)
|
||||||
|
)
|
||||||
throw new BadRequestError({ message: "Invalid db host" });
|
throw new BadRequestError({ message: "Invalid db host" });
|
||||||
return providerInputs;
|
return providerInputs;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { forwardRef, ReactNode } from "react";
|
import { CSSProperties, forwardRef, ReactNode } from "react";
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
export type CardTitleProps = {
|
export type CardTitleProps = {
|
||||||
@@ -31,10 +31,13 @@ export const CardFooter = ({ children, className }: CardFooterProps) => (
|
|||||||
export type CardBodyProps = {
|
export type CardBodyProps = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
style?: CSSProperties;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CardBody = ({ children, className }: CardBodyProps) => (
|
export const CardBody = ({ children, className, style }: CardBodyProps) => (
|
||||||
<div className={twMerge("px-6 pb-6 pt-0", className)}>{children}</div>
|
<div className={twMerge("px-6 pb-6 pt-0", className)} style={style}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
export type CardProps = {
|
export type CardProps = {
|
||||||
@@ -44,10 +47,14 @@ export type CardProps = {
|
|||||||
isRounded?: boolean;
|
isRounded?: boolean;
|
||||||
isPlain?: boolean;
|
isPlain?: boolean;
|
||||||
isHoverable?: boolean;
|
isHoverable?: boolean;
|
||||||
|
style?: CSSProperties;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Card = forwardRef<HTMLDivElement, CardProps>(
|
export const Card = forwardRef<HTMLDivElement, CardProps>(
|
||||||
({ children, isFullHeight, isRounded, isHoverable, isPlain, className }, ref): JSX.Element => {
|
(
|
||||||
|
{ children, isFullHeight, isRounded, isHoverable, isPlain, className, style },
|
||||||
|
ref
|
||||||
|
): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
@@ -59,6 +66,7 @@ export const Card = forwardRef<HTMLDivElement, CardProps>(
|
|||||||
isHoverable && "hover:shadow-xl",
|
isHoverable && "hover:shadow-xl",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
style={style}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -29,12 +29,15 @@ export const ModalContent = forwardRef<HTMLDivElement, ModalContentProps>(
|
|||||||
<Card
|
<Card
|
||||||
isRounded
|
isRounded
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
"thin-scrollbar fixed top-1/2 left-1/2 z-30 max-h-screen max-w-xl -translate-y-2/4 -translate-x-2/4 animate-popIn border border-mineshaft-600 drop-shadow-2xl dark:[color-scheme:dark]",
|
"thin-scrollbar fixed top-1/2 left-1/2 z-30 max-w-xl -translate-y-2/4 -translate-x-2/4 animate-popIn border border-mineshaft-600 drop-shadow-2xl dark:[color-scheme:dark]",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
style={{ maxHeight: "90%" }}
|
||||||
>
|
>
|
||||||
{title && <CardTitle subTitle={subTitle}>{title}</CardTitle>}
|
{title && <CardTitle subTitle={subTitle}>{title}</CardTitle>}
|
||||||
<CardBody>{children}</CardBody>
|
<CardBody className="overflow-y-auto overflow-x-hidden" style={{ maxHeight: "90%" }}>
|
||||||
|
{children}
|
||||||
|
</CardBody>
|
||||||
{footerContent && <CardFooter>{footerContent}</CardFooter>}
|
{footerContent && <CardFooter>{footerContent}</CardFooter>}
|
||||||
<DialogPrimitive.Close aria-label="Close" asChild onClick={onClose}>
|
<DialogPrimitive.Close aria-label="Close" asChild onClick={onClose}>
|
||||||
<IconButton
|
<IconButton
|
||||||
|
|||||||
+3
-3
@@ -11,7 +11,7 @@ import { SqlDatabaseInputForm } from "./SqlDatabaseInputForm";
|
|||||||
type Props = {
|
type Props = {
|
||||||
isOpen?: boolean;
|
isOpen?: boolean;
|
||||||
onToggle: (isOpen: boolean) => void;
|
onToggle: (isOpen: boolean) => void;
|
||||||
projectSlug:string;
|
projectSlug: string;
|
||||||
environment: string;
|
environment: string;
|
||||||
secretPath: string;
|
secretPath: string;
|
||||||
};
|
};
|
||||||
@@ -42,7 +42,7 @@ export const CreateDynamicSecretForm = ({
|
|||||||
<ModalContent
|
<ModalContent
|
||||||
title="Dynamic secret setup"
|
title="Dynamic secret setup"
|
||||||
subTitle="Configure dynamic secret parameters"
|
subTitle="Configure dynamic secret parameters"
|
||||||
className="my-4 max-h-screen max-w-3xl overflow-scroll"
|
className="my-4 max-w-3xl"
|
||||||
>
|
>
|
||||||
<AnimatePresence exitBeforeEnter>
|
<AnimatePresence exitBeforeEnter>
|
||||||
{wizardStep === WizardSteps.SelectProvider && (
|
{wizardStep === WizardSteps.SelectProvider && (
|
||||||
@@ -56,7 +56,7 @@ export const CreateDynamicSecretForm = ({
|
|||||||
<div className="mb-4 text-mineshaft-300">Select a service to connect to:</div>
|
<div className="mb-4 text-mineshaft-300">Select a service to connect to:</div>
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
<div
|
<div
|
||||||
className="flex h-32 w-32 cursor-pointer flex-col items-center space-y-4 rounded border border-mineshaft-500 bg-bunker-600 p-6 transition-all hover:bg-primary/10 hover:border-primary/70 hover:text-white"
|
className="flex h-32 w-32 cursor-pointer flex-col items-center space-y-4 rounded border border-mineshaft-500 bg-bunker-600 p-6 transition-all hover:border-primary/70 hover:bg-primary/10 hover:text-white"
|
||||||
role="button"
|
role="button"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
+225
-229
@@ -25,7 +25,7 @@ const formSchema = z.object({
|
|||||||
provider: z.object({
|
provider: z.object({
|
||||||
client: z.nativeEnum(SqlProviders),
|
client: z.nativeEnum(SqlProviders),
|
||||||
host: z.string().toLowerCase().min(1),
|
host: z.string().toLowerCase().min(1),
|
||||||
port: z.number(),
|
port: z.coerce.number(),
|
||||||
database: z.string().min(1),
|
database: z.string().min(1),
|
||||||
username: z.string().min(1),
|
username: z.string().min(1),
|
||||||
password: z.string().min(1),
|
password: z.string().min(1),
|
||||||
@@ -54,9 +54,7 @@ const formSchema = z.object({
|
|||||||
if (valMs > 24 * 60 * 60 * 1000)
|
if (valMs > 24 * 60 * 60 * 1000)
|
||||||
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
|
||||||
}),
|
}),
|
||||||
name: z
|
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase")
|
||||||
.string()
|
|
||||||
.refine((val) => val.toLowerCase() === val, "Must be lowercase")
|
|
||||||
});
|
});
|
||||||
type TForm = z.infer<typeof formSchema>;
|
type TForm = z.infer<typeof formSchema>;
|
||||||
|
|
||||||
@@ -84,7 +82,7 @@ export const SqlDatabaseInputForm = ({
|
|||||||
defaultValues: {
|
defaultValues: {
|
||||||
provider: {
|
provider: {
|
||||||
creationStatement:
|
creationStatement:
|
||||||
"CREATE USER \"{{username}}\" WITH SUPERUSER ENCRYPTED PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';\nGRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO \"{{username}}\";",
|
"CREATE USER \"{{username}}\" WITH ENCRYPTED PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';\nGRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO \"{{username}}\";",
|
||||||
renewStatement: "ALTER ROLE \"{{username}}\" VALID UNTIL '{{expiration}}';",
|
renewStatement: "ALTER ROLE \"{{username}}\" VALID UNTIL '{{expiration}}';",
|
||||||
revocationStatement:
|
revocationStatement:
|
||||||
'REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM "{{username}}";\nDROP OWNED BY "{{username}}";\nDROP ROLE "{{username}}";'
|
'REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM "{{username}}";\nDROP OWNED BY "{{username}}";\nDROP ROLE "{{username}}";'
|
||||||
@@ -119,238 +117,236 @@ export const SqlDatabaseInputForm = ({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<form onSubmit={handleSubmit(handleCreateDynamicSecret)}>
|
<form onSubmit={handleSubmit(handleCreateDynamicSecret)}>
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<div className="flex-grow">
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
defaultValue=""
|
|
||||||
name="name"
|
|
||||||
render={({ field, fieldState: { error } }) => (
|
|
||||||
<FormControl
|
|
||||||
label="Secret Name"
|
|
||||||
isError={Boolean(error)}
|
|
||||||
errorText={error?.message}
|
|
||||||
>
|
|
||||||
<Input {...field} placeholder="dynamic-postgres" />
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="w-32">
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
name="defaultTTL"
|
|
||||||
defaultValue="1h"
|
|
||||||
render={({ field, fieldState: { error } }) => (
|
|
||||||
<FormControl
|
|
||||||
label={<TtlFormLabel label="Default TTL" />}
|
|
||||||
isError={Boolean(error?.message)}
|
|
||||||
errorText={error?.message}
|
|
||||||
>
|
|
||||||
<Input {...field} />
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="w-32">
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
name="maxTTL"
|
|
||||||
defaultValue="24h"
|
|
||||||
render={({ field, fieldState: { error } }) => (
|
|
||||||
<FormControl
|
|
||||||
label={<TtlFormLabel label="Max TTL" />}
|
|
||||||
isError={Boolean(error?.message)}
|
|
||||||
errorText={error?.message}
|
|
||||||
>
|
|
||||||
<Input {...field} />
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<div className="mb-4 mt-4 border-b border-mineshaft-500 pb-2 pl-1 font-medium text-mineshaft-200">
|
<div className="flex items-center space-x-2">
|
||||||
Configuration
|
<div className="flex-grow">
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
defaultValue=""
|
||||||
|
name="name"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label="Secret Name"
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input {...field} placeholder="dynamic-postgres" />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="w-32">
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="defaultTTL"
|
||||||
|
defaultValue="1h"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label={<TtlFormLabel label="Default TTL" />}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="w-32">
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="maxTTL"
|
||||||
|
defaultValue="24h"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label={<TtlFormLabel label="Max TTL" />}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col">
|
<div>
|
||||||
<div className="pl-1 pb-0.5 text-sm text-mineshaft-400">Service</div>
|
<div className="mb-4 mt-4 border-b border-mineshaft-500 pb-2 pl-1 font-medium text-mineshaft-200">
|
||||||
<Controller
|
Configuration
|
||||||
control={control}
|
|
||||||
name="provider.client"
|
|
||||||
defaultValue={SqlProviders.Postgres}
|
|
||||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
|
||||||
<FormControl isError={Boolean(error?.message)} errorText={error?.message}>
|
|
||||||
<Select
|
|
||||||
value={value}
|
|
||||||
onValueChange={(val) => onChange(val)}
|
|
||||||
className="w-full border border-mineshaft-500"
|
|
||||||
>
|
|
||||||
<SelectItem value={SqlProviders.Postgres}>PostgreSQL</SelectItem>
|
|
||||||
</Select>
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
name="provider.host"
|
|
||||||
defaultValue=""
|
|
||||||
render={({ field, fieldState: { error } }) => (
|
|
||||||
<FormControl
|
|
||||||
label="Host"
|
|
||||||
className="flex-grow"
|
|
||||||
isError={Boolean(error?.message)}
|
|
||||||
errorText={error?.message}
|
|
||||||
>
|
|
||||||
<Input {...field} />
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
name="provider.port"
|
|
||||||
defaultValue={5432}
|
|
||||||
render={({ field, fieldState: { error } }) => (
|
|
||||||
<FormControl
|
|
||||||
label="Port"
|
|
||||||
isError={Boolean(error?.message)}
|
|
||||||
errorText={error?.message}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
{...field}
|
|
||||||
type="number"
|
|
||||||
onChange={(el) => field.onChange(parseInt(el.target.value, 10))}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex flex-col">
|
||||||
|
<div className="pl-1 pb-0.5 text-sm text-mineshaft-400">Service</div>
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
name="provider.username"
|
name="provider.client"
|
||||||
defaultValue=""
|
defaultValue={SqlProviders.Postgres}
|
||||||
render={({ field, fieldState: { error } }) => (
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
<FormControl
|
<FormControl isError={Boolean(error?.message)} errorText={error?.message}>
|
||||||
label="User"
|
<Select
|
||||||
isError={Boolean(error?.message)}
|
value={value}
|
||||||
errorText={error?.message}
|
onValueChange={(val) => onChange(val)}
|
||||||
>
|
className="w-full border border-mineshaft-500"
|
||||||
<Input {...field} />
|
>
|
||||||
|
<SelectItem value={SqlProviders.Postgres}>PostgreSQL</SelectItem>
|
||||||
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Controller
|
<div className="flex items-center space-x-2">
|
||||||
control={control}
|
<Controller
|
||||||
name="provider.password"
|
control={control}
|
||||||
render={({ field, fieldState: { error } }) => (
|
name="provider.host"
|
||||||
<FormControl
|
defaultValue=""
|
||||||
label="Password"
|
render={({ field, fieldState: { error } }) => (
|
||||||
isError={Boolean(error?.message)}
|
<FormControl
|
||||||
errorText={error?.message}
|
label="Host"
|
||||||
>
|
className="flex-grow"
|
||||||
<Input {...field} type="password" />
|
isError={Boolean(error?.message)}
|
||||||
</FormControl>
|
errorText={error?.message}
|
||||||
)}
|
>
|
||||||
/>
|
<Input {...field} />
|
||||||
<Controller
|
</FormControl>
|
||||||
control={control}
|
)}
|
||||||
name="provider.database"
|
/>
|
||||||
defaultValue="default"
|
<Controller
|
||||||
render={({ field, fieldState: { error } }) => (
|
control={control}
|
||||||
<FormControl
|
name="provider.port"
|
||||||
label="Database Name"
|
defaultValue={5432}
|
||||||
isError={Boolean(error?.message)}
|
render={({ field, fieldState: { error } }) => (
|
||||||
errorText={error?.message}
|
<FormControl
|
||||||
>
|
label="Port"
|
||||||
<Input {...field} />
|
isError={Boolean(error?.message)}
|
||||||
</FormControl>
|
errorText={error?.message}
|
||||||
)}
|
>
|
||||||
/>
|
<Input {...field} type="number" />
|
||||||
</div>
|
</FormControl>
|
||||||
<div>
|
)}
|
||||||
<Controller
|
/>
|
||||||
control={control}
|
</div>
|
||||||
name="provider.ca"
|
<div className="flex items-center space-x-2">
|
||||||
render={({ field, fieldState: { error } }) => (
|
<Controller
|
||||||
<FormControl
|
control={control}
|
||||||
isOptional
|
name="provider.username"
|
||||||
label="CA(SSL)"
|
defaultValue=""
|
||||||
isError={Boolean(error?.message)}
|
render={({ field, fieldState: { error } }) => (
|
||||||
errorText={error?.message}
|
<FormControl
|
||||||
>
|
label="User"
|
||||||
<SecretInput
|
isError={Boolean(error?.message)}
|
||||||
{...field}
|
errorText={error?.message}
|
||||||
containerClassName="text-bunker-300 hover:border-primary-400/50 border border-mineshaft-600 bg-mineshaft-900 px-2 py-1.5"
|
>
|
||||||
/>
|
<Input {...field} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Accordion type="single" collapsible className="mb-2 w-full bg-mineshaft-700">
|
<Controller
|
||||||
<AccordionItem value="advance-statements">
|
control={control}
|
||||||
<AccordionTrigger>Modify SQL Statements</AccordionTrigger>
|
name="provider.password"
|
||||||
<AccordionContent>
|
render={({ field, fieldState: { error } }) => (
|
||||||
<Controller
|
<FormControl
|
||||||
control={control}
|
label="Password"
|
||||||
name="provider.creationStatement"
|
isError={Boolean(error?.message)}
|
||||||
render={({ field, fieldState: { error } }) => (
|
errorText={error?.message}
|
||||||
<FormControl
|
>
|
||||||
label="Creation Statement"
|
<Input {...field} type="password" />
|
||||||
isError={Boolean(error?.message)}
|
</FormControl>
|
||||||
errorText={error?.message}
|
)}
|
||||||
helperText="username, password and expiration are dynamically provisioned"
|
/>
|
||||||
>
|
<Controller
|
||||||
<TextArea
|
control={control}
|
||||||
{...field}
|
name="provider.database"
|
||||||
reSize="none"
|
defaultValue="default"
|
||||||
rows={3}
|
render={({ field, fieldState: { error } }) => (
|
||||||
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
|
<FormControl
|
||||||
/>
|
label="Database Name"
|
||||||
</FormControl>
|
isError={Boolean(error?.message)}
|
||||||
)}
|
errorText={error?.message}
|
||||||
/>
|
>
|
||||||
<Controller
|
<Input {...field} />
|
||||||
control={control}
|
</FormControl>
|
||||||
name="provider.revocationStatement"
|
)}
|
||||||
render={({ field, fieldState: { error } }) => (
|
/>
|
||||||
<FormControl
|
</div>
|
||||||
label="Revocation Statement"
|
<div>
|
||||||
isError={Boolean(error?.message)}
|
<Controller
|
||||||
errorText={error?.message}
|
control={control}
|
||||||
helperText="username is dynamically provisioned"
|
name="provider.ca"
|
||||||
>
|
render={({ field, fieldState: { error } }) => (
|
||||||
<TextArea
|
<FormControl
|
||||||
{...field}
|
isOptional
|
||||||
reSize="none"
|
label="CA(SSL)"
|
||||||
rows={3}
|
isError={Boolean(error?.message)}
|
||||||
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
|
errorText={error?.message}
|
||||||
/>
|
>
|
||||||
</FormControl>
|
<SecretInput
|
||||||
)}
|
{...field}
|
||||||
/>
|
containerClassName="text-bunker-300 hover:border-primary-400/50 border border-mineshaft-600 bg-mineshaft-900 px-2 py-1.5"
|
||||||
<Controller
|
/>
|
||||||
control={control}
|
</FormControl>
|
||||||
name="provider.renewStatement"
|
)}
|
||||||
render={({ field, fieldState: { error } }) => (
|
/>
|
||||||
<FormControl
|
<Accordion type="single" collapsible className="mb-2 w-full bg-mineshaft-700">
|
||||||
label="Renew Statement"
|
<AccordionItem value="advance-statements">
|
||||||
helperText="username and expiration are dynamically provisioned"
|
<AccordionTrigger>Modify SQL Statements</AccordionTrigger>
|
||||||
isError={Boolean(error?.message)}
|
<AccordionContent>
|
||||||
errorText={error?.message}
|
<Controller
|
||||||
>
|
control={control}
|
||||||
<TextArea
|
name="provider.creationStatement"
|
||||||
{...field}
|
render={({ field, fieldState: { error } }) => (
|
||||||
reSize="none"
|
<FormControl
|
||||||
rows={3}
|
label="Creation Statement"
|
||||||
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
|
isError={Boolean(error?.message)}
|
||||||
/>
|
errorText={error?.message}
|
||||||
</FormControl>
|
helperText="username, password and expiration are dynamically provisioned"
|
||||||
)}
|
>
|
||||||
/>
|
<TextArea
|
||||||
</AccordionContent>
|
{...field}
|
||||||
</AccordionItem>
|
reSize="none"
|
||||||
</Accordion>
|
rows={3}
|
||||||
|
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="provider.revocationStatement"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label="Revocation Statement"
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
errorText={error?.message}
|
||||||
|
helperText="username is dynamically provisioned"
|
||||||
|
>
|
||||||
|
<TextArea
|
||||||
|
{...field}
|
||||||
|
reSize="none"
|
||||||
|
rows={3}
|
||||||
|
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="provider.renewStatement"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label="Renew Statement"
|
||||||
|
helperText="username and expiration are dynamically provisioned"
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<TextArea
|
||||||
|
{...field}
|
||||||
|
reSize="none"
|
||||||
|
rows={3}
|
||||||
|
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user