Merge pull request #4727 from Infisical/fix-resource-account-rotation-form

fix: allow rotation account credentials to be removed from resources
This commit is contained in:
Andre
2025-10-24 19:11:09 -04:00
committed by GitHub

View File

@@ -1,38 +1,74 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Controller, useFormContext, useWatch } from "react-hook-form"; import { Controller, useFormContext, useWatch } from "react-hook-form";
import { import { FormControl, Input, Switch } from "@app/components/v2";
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
FormControl,
Input
} from "@app/components/v2";
import { UNCHANGED_PASSWORD_SENTINEL } from "@app/hooks/api/pam/constants"; import { UNCHANGED_PASSWORD_SENTINEL } from "@app/hooks/api/pam/constants";
export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => { export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => {
const { control } = useFormContext(); const { control, setValue, getValues } = useFormContext();
const [showPassword, setShowPassword] = useState(false); const [showPassword, setShowPassword] = useState(false);
const password = useWatch({ control, name: "credentials.password" }); const password = useWatch({ control, name: "credentials.password" });
const rotationUsername = useWatch({ control, name: "rotationAccountCredentials.username" });
const rotationPassword = useWatch({ control, name: "rotationAccountCredentials.password" });
const [enabled, setEnabled] = useState(false);
const [wasRotationPasswordSentinelInitially, setWasRotationPasswordSentinelInitially] =
useState(false);
useEffect(() => {
const initialRotationPass = getValues("rotationAccountCredentials.password");
if (initialRotationPass === UNCHANGED_PASSWORD_SENTINEL) {
setWasRotationPasswordSentinelInitially(true);
}
}, [getValues]);
useEffect(() => { useEffect(() => {
if (password === UNCHANGED_PASSWORD_SENTINEL) { if (password === UNCHANGED_PASSWORD_SENTINEL) {
setShowPassword(false); setShowPassword(false);
} }
}, [password]); }, [password]);
useEffect(() => {
const isUsernamePopulated = rotationUsername && rotationUsername !== "";
const isPasswordPopulated =
rotationPassword &&
rotationPassword !== "" &&
rotationPassword !== UNCHANGED_PASSWORD_SENTINEL;
if (isUsernamePopulated || isPasswordPopulated) {
setEnabled(true);
}
}, [rotationUsername, rotationPassword]);
return ( return (
<Accordion type="single" collapsible className="w-full"> <div className="flex flex-col gap-2">
<AccordionItem value="advance-settings" className="data-[state=open]:border-none"> <Switch
<AccordionTrigger className="h-fit flex-none pl-1 text-sm"> id="account-rotation"
<div className="order-1 ml-3">Rotation Account</div> onCheckedChange={(value) => {
</AccordionTrigger> setEnabled(value);
<AccordionContent childrenClassName="px-0 py-0"> if (value) {
<p className="mb-2 text-xs"> setValue("rotationAccountCredentials.username", "", {
Credentials of the privileged account which will be used for rotating other accounts shouldDirty: true
under this resource });
</p> setValue("rotationAccountCredentials.password", "", {
shouldDirty: true
});
} else {
setValue("rotationAccountCredentials", null, {
shouldDirty: true
});
}
}}
isChecked={enabled}
containerClassName="flex-row-reverse w-fit"
className="ml-0"
>
<p className="ml-2">Credential Rotation</p>
</Switch>
{enabled && (
<>
<div className="flex gap-2"> <div className="flex gap-2">
<Controller <Controller
name="rotationAccountCredentials.username" name="rotationAccountCredentials.username"
@@ -44,7 +80,9 @@ export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => {
isError={Boolean(error?.message)} isError={Boolean(error?.message)}
label="Username" label="Username"
> >
<Input {...field} autoComplete="off" /> <div className="relative">
<Input {...field} autoComplete="off" />
</div>
</FormControl> </FormControl>
)} )}
/> />
@@ -58,29 +96,40 @@ export const SqlRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => {
isError={Boolean(error?.message)} isError={Boolean(error?.message)}
label="Password" label="Password"
> >
<Input <div className="relative">
{...field} <Input
type={showPassword ? "text" : "password"} {...field}
autoComplete="new-password" type={showPassword ? "text" : "password"}
onFocus={() => { autoComplete="new-password"
if (isUpdate && field.value === UNCHANGED_PASSWORD_SENTINEL) { onFocus={() => {
field.onChange(""); if (isUpdate && field.value === UNCHANGED_PASSWORD_SENTINEL) {
} field.onChange("");
setShowPassword(true); }
}} setShowPassword(true);
onBlur={() => { }}
if (isUpdate && field.value === "") { onBlur={() => {
field.onChange(UNCHANGED_PASSWORD_SENTINEL); if (
} isUpdate &&
setShowPassword(false); field.value === "" &&
}} wasRotationPasswordSentinelInitially
/> ) {
field.onChange(UNCHANGED_PASSWORD_SENTINEL);
}
setShowPassword(false);
}}
/>
</div>
</FormControl> </FormControl>
)} )}
/> />
</div> </div>
</AccordionContent>
</AccordionItem> <p className="mb-2 text-xs text-mineshaft-400">
</Accordion> Credentials of the privileged account which will be used for rotating other accounts
under this resource
</p>
</>
)}
</div>
); );
}; };