mirror of
https://github.com/Infisical/infisical.git
synced 2025-07-20 01:48:03 +00:00
Compare commits
9 Commits
fix/improv
...
fix/postgr
Author | SHA1 | Date | |
---|---|---|---|
b4ef55db4e | |||
307b5d1f87 | |||
54087038c2 | |||
f835bf0ba8 | |||
c79ea0631e | |||
948799822f | |||
c14a431177 | |||
c4e08b9811 | |||
7784b8a81c |
Binary file not shown.
Before Width: | Height: | Size: 865 KiB After Width: | Height: | Size: 894 KiB |
Binary file not shown.
Before Width: | Height: | Size: 652 KiB After Width: | Height: | Size: 666 KiB |
Binary file not shown.
Before Width: | Height: | Size: 507 KiB After Width: | Height: | Size: 447 KiB |
@ -30,6 +30,14 @@ Infisical supports connecting to PostgreSQL using a database role.
|
|||||||
-- enable permissions to alter login credentials
|
-- enable permissions to alter login credentials
|
||||||
ALTER ROLE infisical_role WITH CREATEROLE;
|
ALTER ROLE infisical_role WITH CREATEROLE;
|
||||||
```
|
```
|
||||||
|
<Tip>
|
||||||
|
In some configurations, the role performing the rotation must be explicitly granted access to manage each user. To do this, grant the user's role to the rotation role with:
|
||||||
|
```SQL
|
||||||
|
-- grant each user role to admin user for password rotation
|
||||||
|
GRANT <secret_rotation_user> TO <infisical_role> WITH ADMIN OPTION;
|
||||||
|
```
|
||||||
|
Replace `<secret_rotation_user>` with each specific username whose credentials will be rotated, and `<infisical_role>` with the role that will perform the rotation.
|
||||||
|
</Tip>
|
||||||
</Tab>
|
</Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Step>
|
</Step>
|
||||||
|
@ -43,6 +43,7 @@ export type TSecretApprovalRequest = {
|
|||||||
isReplicated?: boolean;
|
isReplicated?: boolean;
|
||||||
slug: string;
|
slug: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
committerUserId: string;
|
committerUserId: string;
|
||||||
reviewers: {
|
reviewers: {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
@ -76,6 +76,7 @@ export const CertificateTemplateEnrollmentModal = ({ popUp, handlePopUpToggle }:
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (data) {
|
if (data) {
|
||||||
reset({
|
reset({
|
||||||
|
method: EnrollmentMethod.EST,
|
||||||
caChain: data.caChain,
|
caChain: data.caChain,
|
||||||
isEnabled: data.isEnabled,
|
isEnabled: data.isEnabled,
|
||||||
disableBootstrapCertValidation: data.disableBootstrapCertValidation
|
disableBootstrapCertValidation: data.disableBootstrapCertValidation
|
||||||
|
@ -3,6 +3,7 @@ import { Helmet } from "react-helmet";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import {
|
import {
|
||||||
faCertificate,
|
faCertificate,
|
||||||
|
faCog,
|
||||||
faEllipsis,
|
faEllipsis,
|
||||||
faPencil,
|
faPencil,
|
||||||
faPlus,
|
faPlus,
|
||||||
@ -12,6 +13,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
|
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||||
import { createNotification } from "@app/components/notifications";
|
import { createNotification } from "@app/components/notifications";
|
||||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||||
import {
|
import {
|
||||||
@ -40,12 +42,14 @@ import {
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionPkiTemplateActions,
|
ProjectPermissionPkiTemplateActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
|
useSubscription,
|
||||||
useWorkspace
|
useWorkspace
|
||||||
} from "@app/context";
|
} from "@app/context";
|
||||||
import { usePopUp } from "@app/hooks";
|
import { usePopUp } from "@app/hooks";
|
||||||
import { useDeleteCertTemplateV2 } from "@app/hooks/api";
|
import { useDeleteCertTemplateV2 } from "@app/hooks/api";
|
||||||
import { useListCertificateTemplates } from "@app/hooks/api/certificateTemplates/queries";
|
import { useListCertificateTemplates } from "@app/hooks/api/certificateTemplates/queries";
|
||||||
|
|
||||||
|
import { CertificateTemplateEnrollmentModal } from "../CertificatesPage/components/CertificateTemplateEnrollmentModal";
|
||||||
import { PkiTemplateForm } from "./components/PkiTemplateForm";
|
import { PkiTemplateForm } from "./components/PkiTemplateForm";
|
||||||
|
|
||||||
const PER_PAGE_INIT = 25;
|
const PER_PAGE_INIT = 25;
|
||||||
@ -56,9 +60,13 @@ export const PkiTemplateListPage = () => {
|
|||||||
const [perPage, setPerPage] = useState(PER_PAGE_INIT);
|
const [perPage, setPerPage] = useState(PER_PAGE_INIT);
|
||||||
const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([
|
const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([
|
||||||
"certificateTemplate",
|
"certificateTemplate",
|
||||||
"deleteTemplate"
|
"deleteTemplate",
|
||||||
|
"enrollmentOptions",
|
||||||
|
"estUpgradePlan"
|
||||||
] as const);
|
] as const);
|
||||||
|
|
||||||
|
const { subscription } = useSubscription();
|
||||||
|
|
||||||
const { data, isPending } = useListCertificateTemplates({
|
const { data, isPending } = useListCertificateTemplates({
|
||||||
projectId: currentWorkspace.id,
|
projectId: currentWorkspace.id,
|
||||||
offset: (page - 1) * perPage,
|
offset: (page - 1) * perPage,
|
||||||
@ -92,7 +100,7 @@ export const PkiTemplateListPage = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>{t("common.head-title", { title: "PKI Subscribers" })}</title>
|
<title>{t("common.head-title", { title: "PKI Templates" })}</title>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
<div className="h-full bg-bunker-800">
|
<div className="h-full bg-bunker-800">
|
||||||
<div className="container mx-auto flex flex-col justify-between text-white">
|
<div className="container mx-auto flex flex-col justify-between text-white">
|
||||||
@ -177,7 +185,33 @@ export const PkiTemplateListPage = () => {
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
</ProjectPermissionCan>
|
</ProjectPermissionCan>
|
||||||
|
<ProjectPermissionCan
|
||||||
|
I={ProjectPermissionPkiTemplateActions.Edit}
|
||||||
|
a={ProjectPermissionSub.CertificateTemplates}
|
||||||
|
>
|
||||||
|
{(isAllowed) => (
|
||||||
|
<DropdownMenuItem
|
||||||
|
className={twMerge(
|
||||||
|
!isAllowed &&
|
||||||
|
"pointer-events-none cursor-not-allowed opacity-50"
|
||||||
|
)}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
if (!subscription.pkiEst) {
|
||||||
|
handlePopUpOpen("estUpgradePlan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handlePopUpOpen("enrollmentOptions", {
|
||||||
|
id: template.id
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
disabled={!isAllowed}
|
||||||
|
icon={<FontAwesomeIcon icon={faCog} />}
|
||||||
|
>
|
||||||
|
Manage Enrollment
|
||||||
|
</DropdownMenuItem>
|
||||||
|
)}
|
||||||
|
</ProjectPermissionCan>
|
||||||
<ProjectPermissionCan
|
<ProjectPermissionCan
|
||||||
I={ProjectPermissionPkiTemplateActions.Delete}
|
I={ProjectPermissionPkiTemplateActions.Delete}
|
||||||
a={ProjectPermissionSub.CertificateTemplates}
|
a={ProjectPermissionSub.CertificateTemplates}
|
||||||
@ -251,7 +285,13 @@ export const PkiTemplateListPage = () => {
|
|||||||
/>
|
/>
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<CertificateTemplateEnrollmentModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||||
</div>
|
</div>
|
||||||
|
<UpgradePlanModal
|
||||||
|
isOpen={popUp.estUpgradePlan.isOpen}
|
||||||
|
onOpenChange={(isOpen) => handlePopUpToggle("estUpgradePlan", isOpen)}
|
||||||
|
text="You can only configure template enrollment methods if you switch to Infisical's Enterprise plan."
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -6,16 +6,19 @@ import {
|
|||||||
faCheckCircle,
|
faCheckCircle,
|
||||||
faChevronDown,
|
faChevronDown,
|
||||||
faCodeBranch,
|
faCodeBranch,
|
||||||
|
faCodeMerge,
|
||||||
faMagnifyingGlass,
|
faMagnifyingGlass,
|
||||||
faSearch
|
faSearch,
|
||||||
|
faXmark
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { useSearch } from "@tanstack/react-router";
|
import { useSearch } from "@tanstack/react-router";
|
||||||
import { formatDistance } from "date-fns";
|
import { format, formatDistance } from "date-fns";
|
||||||
import { AnimatePresence, motion } from "framer-motion";
|
import { AnimatePresence, motion } from "framer-motion";
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
Badge,
|
||||||
Button,
|
Button,
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
@ -25,7 +28,8 @@ import {
|
|||||||
EmptyState,
|
EmptyState,
|
||||||
Input,
|
Input,
|
||||||
Pagination,
|
Pagination,
|
||||||
Skeleton
|
Skeleton,
|
||||||
|
Tooltip
|
||||||
} from "@app/components/v2";
|
} from "@app/components/v2";
|
||||||
import { ROUTE_PATHS } from "@app/const/routes";
|
import { ROUTE_PATHS } from "@app/const/routes";
|
||||||
import {
|
import {
|
||||||
@ -308,7 +312,9 @@ export const SecretApprovalRequest = () => {
|
|||||||
createdAt,
|
createdAt,
|
||||||
reviewers,
|
reviewers,
|
||||||
status,
|
status,
|
||||||
committerUser
|
committerUser,
|
||||||
|
hasMerged,
|
||||||
|
updatedAt
|
||||||
} = secretApproval;
|
} = secretApproval;
|
||||||
const isReviewed = reviewers.some(
|
const isReviewed = reviewers.some(
|
||||||
({ status: reviewStatus, userId }) =>
|
({ status: reviewStatus, userId }) =>
|
||||||
@ -317,7 +323,7 @@ export const SecretApprovalRequest = () => {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={reqId}
|
key={reqId}
|
||||||
className="flex flex-col border-b border-mineshaft-600 px-8 py-3 last:border-b-0 hover:bg-mineshaft-700"
|
className="flex border-b border-mineshaft-600 px-8 py-3 last:border-b-0 hover:bg-mineshaft-700"
|
||||||
role="button"
|
role="button"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onClick={() => setSelectedApprovalId(secretApproval.id)}
|
onClick={() => setSelectedApprovalId(secretApproval.id)}
|
||||||
@ -325,29 +331,46 @@ export const SecretApprovalRequest = () => {
|
|||||||
if (evt.key === "Enter") setSelectedApprovalId(secretApproval.id);
|
if (evt.key === "Enter") setSelectedApprovalId(secretApproval.id);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="mb-1 text-sm">
|
<div className="flex flex-col">
|
||||||
<FontAwesomeIcon
|
<div className="mb-1 text-sm">
|
||||||
icon={faCodeBranch}
|
<FontAwesomeIcon
|
||||||
size="sm"
|
icon={faCodeBranch}
|
||||||
className="mr-1.5 text-mineshaft-300"
|
size="sm"
|
||||||
/>
|
className="mr-1.5 text-mineshaft-300"
|
||||||
{secretApproval.isReplicated
|
/>
|
||||||
? `${commits.length} secret pending import`
|
{secretApproval.isReplicated
|
||||||
: generateCommitText(commits)}
|
? `${commits.length} secret pending import`
|
||||||
<span className="text-xs text-bunker-300"> #{secretApproval.slug}</span>
|
: generateCommitText(commits)}
|
||||||
|
<span className="text-xs text-bunker-300"> #{secretApproval.slug}</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-xs leading-3 text-gray-500">
|
||||||
|
Opened {formatDistance(new Date(createdAt), new Date())} ago by{" "}
|
||||||
|
{committerUser ? (
|
||||||
|
<>
|
||||||
|
{committerUser?.firstName || ""} {committerUser?.lastName || ""} (
|
||||||
|
{committerUser?.email})
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<span className="text-gray-600">Deleted User</span>
|
||||||
|
)}
|
||||||
|
{!isReviewed && status === "open" && " - Review required"}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-xs leading-3 text-gray-500">
|
{status === "close" && (
|
||||||
Opened {formatDistance(new Date(createdAt), new Date())} ago by{" "}
|
<Tooltip
|
||||||
{committerUser ? (
|
content={updatedAt ? format(new Date(updatedAt), "M/dd/yyyy h:mm a") : ""}
|
||||||
<>
|
>
|
||||||
{committerUser?.firstName || ""} {committerUser?.lastName || ""} (
|
<div className="my-auto ml-auto">
|
||||||
{committerUser?.email})
|
<Badge
|
||||||
</>
|
variant={hasMerged ? "success" : "danger"}
|
||||||
) : (
|
className="flex h-min items-center gap-1"
|
||||||
<span className="text-gray-600">Deleted User</span>
|
>
|
||||||
)}
|
<FontAwesomeIcon icon={hasMerged ? faCodeMerge : faXmark} />
|
||||||
{!isReviewed && status === "open" && " - Review required"}
|
{hasMerged ? "Merged" : "Rejected"}
|
||||||
</span>
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
Reference in New Issue
Block a user