import Link from "next/link"; import { faArrowsSpin, faArrowUpRightFromSquare, faExclamationTriangle, faFolder, faInfoCircle, faPlus, faRotate, faTrash } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { formatDistance } from "date-fns"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; import { DeleteActionModal, EmptyState, IconButton, Skeleton, Spinner, Table, TableContainer, TableSkeleton, TBody, Td, Th, THead, Tooltip, Tr, UpgradePlanModal } from "@app/components/v2"; import { ProjectPermissionActions, ProjectPermissionSub, useProjectPermission, useSubscription, useWorkspace } from "@app/context"; import { withProjectPermission } from "@app/hoc"; import { usePopUp } from "@app/hooks"; import { useDeleteSecretRotation, useGetSecretRotationProviders, useGetSecretRotations, useRestartSecretRotation } from "@app/hooks/api"; import { TSecretRotationProviderTemplate } from "@app/hooks/api/types"; import { CreateRotationForm } from "./components/CreateRotationForm"; export const SecretRotationPage = withProjectPermission( () => { const { currentWorkspace } = useWorkspace(); const { permission } = useProjectPermission(); const { popUp, handlePopUpOpen, handlePopUpToggle, handlePopUpClose } = usePopUp([ "createRotation", "activeBot", "deleteRotation", "upgradePlan" ] as const); const workspaceId = currentWorkspace?.id || ""; const canCreateRotation = permission.can( ProjectPermissionActions.Create, ProjectPermissionSub.SecretRotation ); const { subscription } = useSubscription(); const { data: secretRotationProviders, isLoading: isRotationProviderLoading } = useGetSecretRotationProviders({ workspaceId }); const { data: secretRotations, isLoading: isRotationLoading } = useGetSecretRotations({ workspaceId }); const { mutateAsync: deleteSecretRotation, variables: deleteSecretRotationVars, isLoading: isDeletingRotation } = useDeleteSecretRotation(); const { mutateAsync: restartSecretRotation, variables: restartSecretRotationVar, isLoading: isRestartingRotation } = useRestartSecretRotation(); const handleDeleteRotation = async () => { const { id } = popUp.deleteRotation.data as { id: string }; try { await deleteSecretRotation({ id, workspaceId }); handlePopUpClose("deleteRotation"); createNotification({ type: "success", text: "Successfully removed rotation" }); } catch (error) { console.log(error); createNotification({ type: "error", text: "Failed to remove rotation" }); } }; const handleRestartRotation = async (id: string) => { try { await restartSecretRotation({ id, workspaceId }); createNotification({ type: "success", text: "Secret rotation initiated" }); } catch (error) { console.log(error); createNotification({ type: "error", text: "Failed to restart rotation" }); } }; const handleCreateRotation = async (provider: TSecretRotationProviderTemplate) => { if (subscription && !subscription?.secretRotation) { handlePopUpOpen("upgradePlan"); return; } if (!canCreateRotation) { createNotification({ type: "error", text: "Access permission denied!!" }); return; } handlePopUpOpen("createRotation", provider); }; return (

Secret Rotation

Stop manually rotating secrets and automate credential rotation.

Documentation{" "}
Rotated Secrets
{isRotationLoading && ( )} {!isRotationLoading && secretRotations?.length === 0 && ( )} {secretRotations?.map( ({ environment, secretPath, outputs, provider, id, lastRotatedAt, status, statusMessage }) => { const isDeleting = deleteSecretRotationVars?.id === id && isDeletingRotation; const isRestarting = restartSecretRotationVar?.id === id && isRestartingRotation; return ( ); } )}
Secret Name Environment Provider Status Last Rotation Action
{outputs .map(({ key }) => key) .join(",") .toUpperCase()}
{environment.slug}
{secretPath}
{provider}
{status} {status === "failed" && ( )}
{lastRotatedAt ? formatDistance(new Date(lastRotatedAt), new Date()) : "-"}
{(isAllowed) => ( handleRestartRotation(id)} > {isRestarting ? ( ) : ( )} )} {(isAllowed) => ( handlePopUpOpen("deleteRotation", { id })} > {isDeleting ? ( ) : ( )} )}
Infisical Rotation Providers
{isRotationProviderLoading && Array.from({ length: 12 }).map((_, index) => ( ))} {!isRotationProviderLoading && secretRotationProviders?.providers.map((provider) => (
{ if (evt.key === "Enter") handlePopUpOpen("createRotation", provider); }} onClick={() => handleCreateRotation(provider)} > rotation provider logo
{provider.title}
))}
Request or create your own template
handlePopUpToggle("createRotation", isOpen)} provider={(popUp.createRotation.data as TSecretRotationProviderTemplate) || {}} /> handlePopUpToggle("deleteRotation", isOpen)} deleteKey="delete" onDeleteApproved={handleDeleteRotation} /> handlePopUpToggle("upgradePlan", isOpen)} text="You can add secret rotation if you switch to Infisical's Team plan." />
); }, { action: ProjectPermissionActions.Read, subject: ProjectPermissionSub.SecretRotation } );