Merge origin/main to feat/pki-sync-v2

This commit is contained in:
Carlos Monastyrski
2025-10-29 13:24:37 -03:00
276 changed files with 2996 additions and 2313 deletions
@@ -7,7 +7,6 @@ import { twMerge } from "tailwind-merge";
import { ProjectPermissionCan } from "@app/components/permissions";
import {
Badge,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
@@ -22,6 +21,7 @@ import {
THead,
Tr
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
import { useGetCaCerts } from "@app/hooks/api";
@@ -60,7 +60,7 @@ export const CaCertificatesTable = ({ caId }: Props) => {
<div className="flex items-center">
CA Certificate {caCert.version}
{isLastItem && (
<Badge variant="success" className="ml-4">
<Badge variant="info" className="ml-4">
Current
</Badge>
)}
@@ -6,7 +6,6 @@ import { twMerge } from "tailwind-merge";
import { ProjectPermissionCan } from "@app/components/permissions";
import {
Badge,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
@@ -22,6 +21,7 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context";
import { CaStatus, CaType, useListCasByTypeAndProjectId } from "@app/hooks/api";
import {
@@ -10,7 +10,6 @@ import { twMerge } from "tailwind-merge";
import { ProjectPermissionCan } from "@app/components/permissions";
import {
Badge,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
@@ -26,6 +25,7 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context";
import { CaStatus, CaType, useListExternalCasByProjectId } from "@app/hooks/api";
import { caStatusToNameMap, getCaStatusBadgeVariant } from "@app/hooks/api/ca/constants";
@@ -104,6 +104,7 @@ export const CertificateTemplatesSection = ({ caId }: Props) => {
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature}
text="Managing template enrollment options for EST is only available on Infisical's Enterprise plan."
/>
</div>
@@ -36,6 +36,7 @@ type Props = {
data?: {
id?: string;
name?: string;
isEnterpriseFeature?: boolean;
}
) => void;
};
@@ -90,7 +91,9 @@ export const CertificateTemplatesTable = ({ handlePopUpOpen, caId }: Props) => {
<DropdownMenuItem
onClick={() => {
if (!subscription?.pkiEst) {
handlePopUpOpen("upgradePlan");
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true
});
return;
}
@@ -6,18 +6,17 @@ import {
faEye,
faFileExport,
faLink,
faQuestionCircle,
faRedo,
faTrash
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { format } from "date-fns";
import { CircleQuestionMarkIcon } from "lucide-react";
import { twMerge } from "tailwind-merge";
import { createNotification } from "@app/components/notifications";
import { ProjectPermissionCan } from "@app/components/permissions";
import {
Badge,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
@@ -34,6 +33,7 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import {
ProjectPermissionCertificateActions,
ProjectPermissionSub,
@@ -60,7 +60,7 @@ const isExpiringWithinOneDay = (notAfter: string): boolean => {
const getAutoRenewalInfo = (certificate: TCertificate) => {
if (certificate.renewedByCertificateId) {
return { text: "Renewed", variant: "instance" as const };
return { text: "Renewed", variant: "neutral" as const };
}
const isRevoked = certificate.status === CertStatus.REVOKED;
@@ -71,7 +71,7 @@ const getAutoRenewalInfo = (certificate: TCertificate) => {
if (isRevoked) {
return {
text: "Not Available",
variant: "instance" as const,
variant: "neutral" as const,
tooltip: "Renewal is not available for revoked certificates"
};
}
@@ -79,7 +79,7 @@ const getAutoRenewalInfo = (certificate: TCertificate) => {
if (isExpired) {
return {
text: "Not Available",
variant: "instance" as const,
variant: "neutral" as const,
tooltip: "Renewal is not available for expired certificates"
};
}
@@ -87,7 +87,7 @@ const getAutoRenewalInfo = (certificate: TCertificate) => {
if (hasNoProfile) {
return {
text: "Not Available",
variant: "instance" as const,
variant: "neutral" as const,
tooltip: "Renewal requires a certificate profile"
};
}
@@ -95,7 +95,7 @@ const getAutoRenewalInfo = (certificate: TCertificate) => {
if (certificate.hasPrivateKey === false) {
return {
text: "Not Available",
variant: "instance" as const,
variant: "neutral" as const,
tooltip: "Renewal is not available for certificates with externally generated private keys"
};
}
@@ -103,7 +103,7 @@ const getAutoRenewalInfo = (certificate: TCertificate) => {
if (isExpiringWithinDay) {
return {
text: "Not Available",
variant: "instance" as const,
variant: "neutral" as const,
tooltip: "Auto-renewal is not available for certificates expiring within 24 hours"
};
}
@@ -117,7 +117,7 @@ const getAutoRenewalInfo = (certificate: TCertificate) => {
}
if (!certificate.renewBeforeDays) {
return { text: "Auto-Renewal Disabled", variant: "primary" as const };
return { text: "Auto-Renewal Disabled", variant: "warning" as const };
}
const notAfterDate = new Date(certificate.notAfter);
@@ -135,11 +135,11 @@ const getAutoRenewalInfo = (certificate: TCertificate) => {
);
if (daysUntilRenewal === 0) {
return { text: "Renews today", variant: "primary" as const };
return { text: "Renews today", variant: "warning" as const };
}
if (daysUntilRenewal <= 7) {
return { text: `Renews in ${daysUntilRenewal}d`, variant: "primary" as const };
return { text: `Renews in ${daysUntilRenewal}d`, variant: "warning" as const };
}
return { text: `Renews in ${daysUntilRenewal}d`, variant: "success" as const };
@@ -282,16 +282,12 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => {
{autoRenewalInfo &&
(autoRenewalInfo.tooltip ? (
<div className="flex items-center gap-2">
<Badge variant={autoRenewalInfo.variant}>
{autoRenewalInfo.text}
<Tooltip content={autoRenewalInfo.tooltip}>
<FontAwesomeIcon
icon={faQuestionCircle}
className="ml-1 cursor-help text-red-400 hover:text-red-300"
size="sm"
/>
</Tooltip>
</Badge>
<Tooltip content={autoRenewalInfo.tooltip}>
<Badge variant={autoRenewalInfo.variant}>
{autoRenewalInfo.text}
<CircleQuestionMarkIcon />
</Badge>
</Tooltip>
</div>
) : (
<Badge variant={autoRenewalInfo.variant}>{autoRenewalInfo.text}</Badge>
@@ -5,13 +5,13 @@ export const getCertValidUntilBadgeDetails = (notAfter: string) => {
const notAfterDate = new Date(notAfter).getTime();
const diffInMs = notAfterDate - currentDate;
let variant: "success" | "primary" | "danger" = "success";
let variant: "success" | "warning" | "danger" = "success";
let label = "Healthy";
if (diffInMs > ms("60d")) {
variant = "success";
} else if (diffInMs > ms("30d")) {
variant = "primary";
variant = "warning";
} else {
variant = "danger";
}
@@ -1,7 +1,6 @@
import { useCallback, useMemo } from "react";
import { subject } from "@casl/ability";
import {
faBan,
faCalendarCheck,
faCheck,
faCopy,
@@ -19,6 +18,7 @@ import {
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNavigate } from "@tanstack/react-router";
import { format } from "date-fns";
import { BanIcon } from "lucide-react";
import { twMerge } from "tailwind-merge";
import { createNotification } from "@app/components/notifications";
@@ -29,7 +29,6 @@ import {
PkiSyncStatusBadge
} from "@app/components/pki-syncs";
import {
Badge,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
@@ -39,6 +38,7 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { ROUTE_PATHS } from "@app/const/routes";
import { ProjectPermissionSub } from "@app/context";
import { ProjectPermissionPkiSyncActions } from "@app/context/ProjectPermissionContext/types";
@@ -172,10 +172,7 @@ export const PkiSyncRow = ({
<Td>
<Tooltip content="The PKI subscriber for this sync has been deleted. Configure a new source or remove this sync.">
<div className="w-min">
<Badge
className="flex h-5 w-min items-center gap-1.5 whitespace-nowrap"
variant="primary"
>
<Badge variant="warning">
<FontAwesomeIcon icon={faTriangleExclamation} />
<span>Source Deleted</span>
</Badge>
@@ -234,12 +231,10 @@ export const PkiSyncRow = ({
className="text-xs"
content="Auto-Sync is disabled. Certificate changes in the PKI subscriber will not be automatically synced to the destination."
>
<div>
<Badge className="flex h-5 w-min items-center gap-1.5 bg-mineshaft-400/50 whitespace-nowrap text-bunker-300">
<FontAwesomeIcon icon={faBan} />
{!syncStatus && "Auto-Sync Disabled"}
</Badge>
</div>
<Badge variant="neutral">
<BanIcon />
{!syncStatus && "Auto-Sync Disabled"}
</Badge>
</Tooltip>
)}
{syncOption?.canImportCertificates && <PkiSyncImportStatusBadge mini pkiSync={pkiSync} />}
@@ -1,11 +1,12 @@
import { useCallback, useEffect, useMemo } from "react";
import { faArrowUpRightFromSquare, faBookOpen, faPlus } from "@fortawesome/free-solid-svg-icons";
import { faPlus } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNavigate, useSearch } from "@tanstack/react-router";
import { ProjectPermissionCan } from "@app/components/permissions";
import { CreatePkiSyncModal } from "@app/components/pki-syncs";
import { Button, Spinner } from "@app/components/v2";
import { DocumentationLinkBadge } from "@app/components/v3";
import { ROUTE_PATHS } from "@app/const/routes";
import { ProjectPermissionSub, useProject } from "@app/context";
import { ProjectPermissionPkiSyncActions } from "@app/context/ProjectPermissionContext/types";
@@ -64,21 +65,10 @@ export const PkiSyncsTab = () => {
<div className="mb-4 flex items-center justify-between">
<div>
<div className="flex items-start gap-1">
<p className="text-xl font-medium text-mineshaft-100">Certificate Syncs</p>
<a
href="https://infisical.com/docs/integrations/pki-syncs/overview"
target="_blank"
rel="noopener noreferrer"
>
<div className="mt-[0.32rem] ml-1 inline-block rounded-md bg-yellow/20 px-1.5 text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
<span>Docs</span>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.07rem] ml-1.5 text-[10px]"
/>
</div>
</a>
<div className="flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Certificate Syncs</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/pki/certificate-syncs/overview" />
</div>
</div>
<p className="text-sm text-bunker-300">
Use App Connections to sync certificates to third-party services.
@@ -7,7 +7,6 @@ import { twMerge } from "tailwind-merge";
import { ProjectPermissionCan } from "@app/components/permissions";
import {
Badge,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
@@ -24,6 +23,7 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import {
ProjectPermissionPkiSubscriberActions,
ProjectPermissionSub,
@@ -93,7 +93,7 @@ export const PkiSubscriberCertificatesTable = ({ subscriberName, handlePopUpOpen
}
if (daysUntilExpiry < 30) {
return <Badge variant="primary">Expiring Soon</Badge>;
return <Badge variant="warning">Expiring Soon</Badge>;
}
return <Badge variant="success">Valid</Badge>;
@@ -11,7 +11,6 @@ import { twMerge } from "tailwind-merge";
import { ProjectPermissionCan } from "@app/components/permissions";
import {
Badge,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
@@ -27,6 +26,7 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import {
ProjectPermissionPkiSubscriberActions,
ProjectPermissionSub,
@@ -1,7 +1,6 @@
import { useCallback } from "react";
import { subject } from "@casl/ability";
import {
faBan,
faCheck,
faCopy,
faDownload,
@@ -15,6 +14,7 @@ import {
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNavigate } from "@tanstack/react-router";
import { BanIcon, RefreshCwIcon } from "lucide-react";
import { createNotification } from "@app/components/notifications";
import { ProjectPermissionCan } from "@app/components/permissions";
@@ -26,7 +26,6 @@ import {
PkiSyncRemoveStatusBadge
} from "@app/components/pki-syncs";
import {
Badge,
Button,
DropdownMenu,
DropdownMenuContent,
@@ -35,6 +34,7 @@ import {
IconButton,
Tooltip
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { ROUTE_PATHS } from "@app/const/routes";
import { ProjectPermissionSub } from "@app/context";
import { ProjectPermissionPkiSyncActions } from "@app/context/ProjectPermissionContext/types";
@@ -136,24 +136,19 @@ export const PkiSyncActionTriggers = ({ pkiSync }: Props) => {
{syncOption?.canImportCertificates && <PkiSyncImportStatusBadge pkiSync={pkiSync} />}
<PkiSyncRemoveStatusBadge pkiSync={pkiSync} />
{pkiSync.isAutoSyncEnabled ? (
<Badge
variant="success"
className="flex h-5 w-min items-center gap-1.5 whitespace-nowrap"
>
<FontAwesomeIcon icon={faRotate} />
<span>Auto-Sync Enabled</span>
<Badge variant="info">
<RefreshCwIcon />
Auto-Sync Enabled
</Badge>
) : (
<Tooltip
className="text-xs"
content="Auto-Sync is disabled. Certificate changes in the PKI subscriber will not be automatically synced to the destination."
>
<div>
<Badge className="flex h-5 w-min items-center gap-1.5 bg-mineshaft-400/50 whitespace-nowrap text-bunker-300">
<FontAwesomeIcon icon={faBan} />
<span>Auto-Sync Disabled</span>
</Badge>
</div>
<Badge variant="neutral">
<BanIcon />
Auto-Sync Disabled
</Badge>
</Tooltip>
)}
<div>
@@ -7,7 +7,6 @@ import { createNotification } from "@app/components/notifications";
import { ProjectPermissionCan } from "@app/components/permissions";
import { CertificateManagementModal } from "@app/components/pki-syncs/CertificateManagementModal";
import {
Badge,
EmptyState,
IconButton,
Pagination,
@@ -20,6 +19,7 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { ProjectPermissionSub } from "@app/context";
import { ProjectPermissionPkiSyncActions } from "@app/context/ProjectPermissionContext/types";
import { useListPkiSyncCertificates, useRemoveCertificatesFromPkiSync } from "@app/hooks/api";
@@ -32,7 +32,7 @@ type Props = {
const getSyncStatusVariant = (status?: CertificateSyncStatus | null) => {
if (status === CertificateSyncStatus.Succeeded) return "success";
if (status === CertificateSyncStatus.Failed) return "danger";
if (status === CertificateSyncStatus.Syncing) return "primary";
if (status === CertificateSyncStatus.Syncing) return "neutral";
return "project";
};
@@ -4,7 +4,8 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { ProjectPermissionCan } from "@app/components/permissions";
import { GenericFieldLabel } from "@app/components/secret-syncs";
import { Badge, IconButton } from "@app/components/v2";
import { IconButton } from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { ProjectPermissionSub } from "@app/context";
import { ProjectPermissionPkiSyncActions } from "@app/context/ProjectPermissionContext/types";
import { TPkiSync } from "@app/hooks/api/pkiSyncs";
@@ -1,10 +1,12 @@
/* eslint-disable jsx-a11y/label-has-associated-control */
import { subject } from "@casl/ability";
import { faEdit, faTriangleExclamation } from "@fortawesome/free-solid-svg-icons";
import { faEdit } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { AlertTriangleIcon } from "lucide-react";
import { ProjectPermissionCan } from "@app/components/permissions";
import { Badge, IconButton, Tooltip } from "@app/components/v2";
import { IconButton, Tooltip } from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { ProjectPermissionSub } from "@app/context";
import { ProjectPermissionPkiSyncActions } from "@app/context/ProjectPermissionContext/types";
import { TPkiSync } from "@app/hooks/api/pkiSyncs";
@@ -36,15 +38,10 @@ export const PkiSyncSourceSection = ({ pkiSync, onEditSource }: Props) => {
<div>
{!subscriberId && (
<Tooltip content="The PKI subscriber for this sync has been deleted. Configure a new source or remove this sync.">
<div className="mr-1 inline-block w-min">
<Badge
className="flex h-5 w-min items-center gap-1.5 whitespace-nowrap"
variant="primary"
>
<FontAwesomeIcon icon={faTriangleExclamation} />
<span>Source Deleted</span>
</Badge>
</div>
<Badge variant="danger" className="mr-1">
<AlertTriangleIcon />
Source Deleted
</Badge>
</Tooltip>
)}
<ProjectPermissionCan I={ProjectPermissionPkiSyncActions.Edit} a={permissionSubject}>
@@ -203,7 +203,9 @@ export const PkiTemplateListPage = () => {
onClick={(e) => {
e.stopPropagation();
if (!subscription.pkiEst) {
handlePopUpOpen("estUpgradePlan");
handlePopUpOpen("estUpgradePlan", {
isEnterpriseFeature: true
});
return;
}
handlePopUpOpen("enrollmentOptions", {
@@ -296,6 +298,7 @@ export const PkiTemplateListPage = () => {
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."
isEnterpriseFeature={popUp.estUpgradePlan.data?.isEnterpriseFeature}
/>
</>
);
@@ -12,7 +12,6 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { createNotification } from "@app/components/notifications";
import {
Badge,
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
@@ -21,6 +20,7 @@ import {
Tooltip,
Tr
} from "@app/components/v2";
import { Badge } from "@app/components/v3";
import { useProjectPermission } from "@app/context";
import {
ProjectPermissionActions,
@@ -45,42 +45,26 @@ const MetricsBadges = ({
};
}) => {
if (!metrics) {
return (
<Badge variant="primary" className="text-xs">
No metrics
</Badge>
);
return <Badge variant="warning">No metrics</Badge>;
}
if (metrics.totalCertificates === 0) {
return (
<Badge variant="primary" className="text-xs">
No certificates
</Badge>
);
return <Badge variant="warning">No certificates</Badge>;
}
return (
<>
{metrics.activeCertificates > 0 && (
<Badge variant="success" className="text-xs">
{metrics.activeCertificates} active
</Badge>
<Badge variant="success">{metrics.activeCertificates} active</Badge>
)}
{metrics.expiringCertificates > 0 && (
<Badge variant="primary" className="text-xs">
{metrics.expiringCertificates} expiring
</Badge>
<Badge variant="warning">{metrics.expiringCertificates} expiring</Badge>
)}
{metrics.expiredCertificates > 0 && (
<Badge variant="danger" className="text-xs">
{metrics.expiredCertificates} expired
</Badge>
<Badge variant="danger">{metrics.expiredCertificates} expired</Badge>
)}
{metrics.revokedCertificates > 0 && (
<Badge variant="danger" className="text-xs">
{metrics.revokedCertificates} revoked
</Badge>
<Badge variant="danger">{metrics.revokedCertificates} revoked</Badge>
)}
</>
);
@@ -135,7 +119,7 @@ export const ProfileRow = ({ profile, onEditProfile, onDeleteProfile }: Props) =
const getEnrollmentTypeBadge = (enrollmentType: string) => {
const config = {
api: { variant: "success" as const, label: "API" },
est: { variant: "primary" as const, label: "EST" }
est: { variant: "warning" as const, label: "EST" }
} as const;
const configKey = Object.keys(config).includes(enrollmentType)