feat: initial schema setup

This commit is contained in:
Sheen Capadngan
2024-10-24 00:29:41 +08:00
parent ca3b64bf6c
commit e034aa381a
3 changed files with 162 additions and 56 deletions
@@ -12,6 +12,11 @@ export enum ElasticSearchAuthTypes {
ApiKey = "api-key" ApiKey = "api-key"
} }
export enum LdapCredentialType {
Dynamic = "dynamic",
Static = "static"
}
export const DynamicSecretRedisDBSchema = z.object({ export const DynamicSecretRedisDBSchema = z.object({
host: z.string().trim().toLowerCase(), host: z.string().trim().toLowerCase(),
port: z.number(), port: z.number(),
@@ -174,16 +179,26 @@ export const AzureEntraIDSchema = z.object({
clientSecret: z.string().trim().min(1) clientSecret: z.string().trim().min(1)
}); });
export const LdapSchema = z.object({ export const LdapSchema = z.union([
url: z.string().trim().min(1), z.object({
binddn: z.string().trim().min(1), url: z.string().trim().min(1),
bindpass: z.string().trim().min(1), binddn: z.string().trim().min(1),
ca: z.string().optional(), bindpass: z.string().trim().min(1),
ca: z.string().optional(),
creationLdif: z.string().min(1), credentialType: z.literal(LdapCredentialType.Dynamic).optional().default(LdapCredentialType.Dynamic),
revocationLdif: z.string().min(1), creationLdif: z.string().min(1),
rollbackLdif: z.string().optional() revocationLdif: z.string().min(1),
}); rollbackLdif: z.string().optional()
}),
z.object({
url: z.string().trim().min(1),
binddn: z.string().trim().min(1),
bindpass: z.string().trim().min(1),
ca: z.string().optional(),
credentialType: z.literal(LdapCredentialType.Static),
rotationLdif: z.string().min(1)
})
]);
export enum DynamicSecretProviders { export enum DynamicSecretProviders {
SqlDatabase = "sql-database", SqlDatabase = "sql-database",
@@ -189,7 +189,7 @@ export type TDynamicSecretProvider =
applicationId: string; applicationId: string;
clientSecret: string; clientSecret: string;
}; };
} }
| { | {
type: DynamicSecretProviders.Ldap; type: DynamicSecretProviders.Ldap;
inputs: { inputs: {
@@ -197,13 +197,13 @@ export type TDynamicSecretProvider =
binddn: string; binddn: string;
bindpass: string; bindpass: string;
ca?: string | undefined; ca?: string | undefined;
creationLdif: string; credentialType: string;
revocationLdif: string; creationLdif?: string;
revocationLdif?: string;
rollbackLdif?: string; rollbackLdif?: string;
rotationLdif?: string;
}; };
}; };
;
export type TCreateDynamicSecretDTO = { export type TCreateDynamicSecretDTO = {
projectSlug: string; projectSlug: string;
provider: TDynamicSecretProvider; provider: TDynamicSecretProvider;
@@ -8,21 +8,47 @@ import { z } from "zod";
import { TtlFormLabel } from "@app/components/features"; import { TtlFormLabel } from "@app/components/features";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { Button, FormControl, Input, TextArea } from "@app/components/v2"; import { Button, FormControl, Input, Select, SelectItem, TextArea } from "@app/components/v2";
import { useCreateDynamicSecret } from "@app/hooks/api"; import { useCreateDynamicSecret } from "@app/hooks/api";
import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types"; import { DynamicSecretProviders } from "@app/hooks/api/dynamicSecret/types";
const formSchema = z.object({ enum CredentialType {
provider: z.object({ Dynamic = "dynamic",
url: z.string().trim().min(1), Static = "static"
binddn: z.string().trim().min(1), }
bindpass: z.string().trim().min(1),
ca: z.string().optional(),
creationLdif: z.string().min(1), const credentialTypes = [
revocationLdif: z.string().min(1), {
rollbackLdif: z.string().optional() label: "Dynamic",
}), value: CredentialType.Dynamic
},
{
label: "Static",
value: CredentialType.Static
}
] as const;
const formSchema = z.object({
provider: z.discriminatedUnion("credentialType", [
z.object({
url: z.string().trim().min(1),
binddn: z.string().trim().min(1),
bindpass: z.string().trim().min(1),
ca: z.string().optional(),
credentialType: z.literal(CredentialType.Dynamic),
creationLdif: z.string().min(1),
revocationLdif: z.string().min(1),
rollbackLdif: z.string().optional()
}),
z.object({
url: z.string().trim().min(1),
binddn: z.string().trim().min(1),
bindpass: z.string().trim().min(1),
ca: z.string().optional(),
credentialType: z.literal(CredentialType.Static),
rotationLdif: z.string().min(1)
})
]),
defaultTTL: z.string().superRefine((val, ctx) => { defaultTTL: z.string().superRefine((val, ctx) => {
const valMs = ms(val); const valMs = ms(val);
@@ -67,6 +93,8 @@ export const LdapInputForm = ({
const { const {
control, control,
formState: { isSubmitting }, formState: { isSubmitting },
setValue,
watch,
handleSubmit handleSubmit
} = useForm<TForm>({ } = useForm<TForm>({
resolver: zodResolver(formSchema), resolver: zodResolver(formSchema),
@@ -78,11 +106,14 @@ export const LdapInputForm = ({
ca: "", ca: "",
creationLdif: "", creationLdif: "",
revocationLdif: "", revocationLdif: "",
rollbackLdif: "" rollbackLdif: "",
credentialType: CredentialType.Dynamic
} }
} }
}); });
const selectedCredentialType = watch("provider.credentialType");
const createDynamicSecret = useCreateDynamicSecret(); const createDynamicSecret = useCreateDynamicSecret();
const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => { const handleCreateDynamicSecret = async ({ name, maxTTL, provider, defaultTTL }: TForm) => {
@@ -240,45 +271,105 @@ export const LdapInputForm = ({
<Controller <Controller
control={control} control={control}
name="provider.creationLdif" name="provider.credentialType"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="Creation LDIF" label="Credential Type"
isError={Boolean(error?.message)} isError={Boolean(error?.message)}
errorText={error?.message} errorText={error?.message}
className="w-full"
> >
<TextArea {...field} /> <Select
defaultValue={field.value}
{...field}
className="w-full"
onValueChange={(e) => {
const ldifFields = [
"provider.creationLdif",
"provider.revocationLdif",
"provider.rollbackLdif"
] as const;
ldifFields.forEach((f) => {
setValue(f, "");
});
field.onChange(e);
}}
>
{credentialTypes.map((credentialType) => (
<SelectItem
value={credentialType.value}
key={`credential-type-${credentialType.value}`}
>
{credentialType.label}
</SelectItem>
))}
</Select>
</FormControl> </FormControl>
)} )}
/> />
<Controller {selectedCredentialType === CredentialType.Dynamic && (
control={control} <>
name="provider.revocationLdif" <Controller
render={({ field, fieldState: { error } }) => ( control={control}
<FormControl name="provider.creationLdif"
label="Revocation LDIF" render={({ field, fieldState: { error } }) => (
isError={Boolean(error?.message)} <FormControl
errorText={error?.message} label="Creation LDIF"
> isError={Boolean(error?.message)}
<TextArea {...field} /> errorText={error?.message}
</FormControl> >
)} <TextArea {...field} />
/> </FormControl>
)}
/>
<Controller <Controller
control={control} control={control}
name="provider.rollbackLdif" name="provider.revocationLdif"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="Rollback LDIF" label="Revocation LDIF"
isError={Boolean(error?.message)} isError={Boolean(error?.message)}
errorText={error?.message} errorText={error?.message}
> >
<TextArea {...field} /> <TextArea {...field} />
</FormControl> </FormControl>
)} )}
/> />
<Controller
control={control}
name="provider.rollbackLdif"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Rollback LDIF"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<TextArea {...field} />
</FormControl>
)}
/>
</>
)}
{selectedCredentialType === CredentialType.Static && (
<Controller
control={control}
name="provider.rotationLdif"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Rotation LDIF"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<TextArea {...field} />
</FormControl>
)}
/>
)}
</div> </div>
</div> </div>
</div> </div>