mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 22:28:15 +00:00
misc: add indicators for errors
This commit is contained in:
@@ -88,6 +88,9 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
if (await knex.schema.hasTable(TableName.PkiSubscriber)) {
|
if (await knex.schema.hasTable(TableName.PkiSubscriber)) {
|
||||||
await knex.schema.alterTable(TableName.PkiSubscriber, (t) => {
|
await knex.schema.alterTable(TableName.PkiSubscriber, (t) => {
|
||||||
t.string("ttl").nullable().alter();
|
t.string("ttl").nullable().alter();
|
||||||
|
t.string("lastOperationStatus");
|
||||||
|
t.text("lastOperationMessage");
|
||||||
|
t.string("lastOperationAt");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,4 +167,12 @@ export async function down(knex: Knex): Promise<void> {
|
|||||||
if (hasExternalCATable) {
|
if (hasExternalCATable) {
|
||||||
await knex.schema.dropTable(TableName.ExternalCertificateAuthority);
|
await knex.schema.dropTable(TableName.ExternalCertificateAuthority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (await knex.schema.hasTable(TableName.PkiSubscriber)) {
|
||||||
|
await knex.schema.alterTable(TableName.PkiSubscriber, (t) => {
|
||||||
|
t.dropColumn("lastOperationStatus");
|
||||||
|
t.dropColumn("lastOperationMessage");
|
||||||
|
t.dropColumn("lastOperationAt");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ export const PkiSubscribersSchema = z.object({
|
|||||||
ttl: z.string().nullable().optional(),
|
ttl: z.string().nullable().optional(),
|
||||||
keyUsages: z.string().array(),
|
keyUsages: z.string().array(),
|
||||||
extendedKeyUsages: z.string().array(),
|
extendedKeyUsages: z.string().array(),
|
||||||
status: z.string()
|
status: z.string(),
|
||||||
|
lastOperationStatus: z.string().nullable().optional(),
|
||||||
|
lastOperationMessage: z.string().nullable().optional(),
|
||||||
|
lastOperationAt: z.string().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TPkiSubscribers = z.infer<typeof PkiSubscribersSchema>;
|
export type TPkiSubscribers = z.infer<typeof PkiSubscribersSchema>;
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ export const registerPkiSubscriberRouter = async (server: FastifyZodProvider) =>
|
|||||||
ttl: z
|
ttl: z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.refine((val) => ms(val) > 0, "TTL must be a positive number")
|
.refine((val) => !val || ms(val) > 0, "TTL must be a positive number")
|
||||||
.optional()
|
.optional()
|
||||||
.describe(PKI_SUBSCRIBERS.UPDATE.ttl),
|
.describe(PKI_SUBSCRIBERS.UPDATE.ttl),
|
||||||
keyUsages: z
|
keyUsages: z
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ export const certificateAuthorityDALFactory = (db: TDbClient) => {
|
|||||||
serialNumber: result.internalSerialNumber,
|
serialNumber: result.internalSerialNumber,
|
||||||
maxPathLength: result.internalMaxPathLength,
|
maxPathLength: result.internalMaxPathLength,
|
||||||
keyAlgorithm: result.internalKeyAlgorithm,
|
keyAlgorithm: result.internalKeyAlgorithm,
|
||||||
notBefore: result.internalNotBefore,
|
notBefore: result.internalNotBefore?.toISOString(),
|
||||||
notAfter: result.internalNotAfter,
|
notAfter: result.internalNotAfter?.toISOString(),
|
||||||
activeCaCertId: result.internalActiveCaCertId,
|
activeCaCertId: result.internalActiveCaCertId,
|
||||||
certificateAuthorityId: result.internalCertificateAuthorityId
|
certificateAuthorityId: result.internalCertificateAuthorityId
|
||||||
}
|
}
|
||||||
@@ -232,8 +232,8 @@ export const certificateAuthorityDALFactory = (db: TDbClient) => {
|
|||||||
serialNumber: ca.internalSerialNumber,
|
serialNumber: ca.internalSerialNumber,
|
||||||
maxPathLength: ca.internalMaxPathLength,
|
maxPathLength: ca.internalMaxPathLength,
|
||||||
keyAlgorithm: ca.internalKeyAlgorithm,
|
keyAlgorithm: ca.internalKeyAlgorithm,
|
||||||
notBefore: ca.internalNotBefore,
|
notBefore: ca.internalNotBefore?.toISOString(),
|
||||||
notAfter: ca.internalNotAfter,
|
notAfter: ca.internalNotAfter?.toISOString(),
|
||||||
activeCaCertId: ca.internalActiveCaCertId,
|
activeCaCertId: ca.internalActiveCaCertId,
|
||||||
certificateAuthorityId: ca.internalCertificateAuthorityId
|
certificateAuthorityId: ca.internalCertificateAuthorityId
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { TAppConnectionServiceFactory } from "../app-connection/app-connection-s
|
|||||||
import { TCertificateBodyDALFactory } from "../certificate/certificate-body-dal";
|
import { TCertificateBodyDALFactory } from "../certificate/certificate-body-dal";
|
||||||
import { TCertificateSecretDALFactory } from "../certificate/certificate-secret-dal";
|
import { TCertificateSecretDALFactory } from "../certificate/certificate-secret-dal";
|
||||||
import { TPkiSubscriberDALFactory } from "../pki-subscriber/pki-subscriber-dal";
|
import { TPkiSubscriberDALFactory } from "../pki-subscriber/pki-subscriber-dal";
|
||||||
|
import { SubscriberOperationStatus } from "../pki-subscriber/pki-subscriber-types";
|
||||||
import { AcmeCertificateAuthorityFns } from "./acme/acme-certificate-authority-fns";
|
import { AcmeCertificateAuthorityFns } from "./acme/acme-certificate-authority-fns";
|
||||||
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
|
import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal";
|
||||||
import { CaType } from "./certificate-authority-enums";
|
import { CaType } from "./certificate-authority-enums";
|
||||||
@@ -47,7 +48,7 @@ type TCertificateAuthorityQueueFactoryDep = {
|
|||||||
certificateBodyDAL: Pick<TCertificateBodyDALFactory, "create">;
|
certificateBodyDAL: Pick<TCertificateBodyDALFactory, "create">;
|
||||||
certificateSecretDAL: Pick<TCertificateSecretDALFactory, "create">;
|
certificateSecretDAL: Pick<TCertificateSecretDALFactory, "create">;
|
||||||
queueService: TQueueServiceFactory;
|
queueService: TQueueServiceFactory;
|
||||||
pkiSubscriberDAL: Pick<TPkiSubscriberDALFactory, "findById">;
|
pkiSubscriberDAL: Pick<TPkiSubscriberDALFactory, "findById" | "updateById">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TCertificateAuthorityQueueFactory = ReturnType<typeof certificateAuthorityQueueFactory>;
|
export type TCertificateAuthorityQueueFactory = ReturnType<typeof certificateAuthorityQueueFactory>;
|
||||||
@@ -152,8 +153,20 @@ export const certificateAuthorityQueueFactory = ({
|
|||||||
try {
|
try {
|
||||||
if (caType === CaType.ACME) {
|
if (caType === CaType.ACME) {
|
||||||
await acmeFns.orderSubscriberCertificate(subscriberId);
|
await acmeFns.orderSubscriberCertificate(subscriberId);
|
||||||
|
await pkiSubscriberDAL.updateById(subscriberId, {
|
||||||
|
lastOperationStatus: SubscriberOperationStatus.SUCCESS,
|
||||||
|
lastOperationMessage: "Certificate ordered successfully",
|
||||||
|
lastOperationAt: new Date().toISOString()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e: unknown) {
|
||||||
|
if (e instanceof Error) {
|
||||||
|
await pkiSubscriberDAL.updateById(subscriberId, {
|
||||||
|
lastOperationStatus: SubscriberOperationStatus.FAILED,
|
||||||
|
lastOperationMessage: e.message,
|
||||||
|
lastOperationAt: new Date().toISOString()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
logger.error(e, `CaOrderCertificate Failed [subscriberId=${subscriberId}] [job=${job.name}]`);
|
logger.error(e, `CaOrderCertificate Failed [subscriberId=${subscriberId}] [job=${job.name}]`);
|
||||||
} finally {
|
} finally {
|
||||||
await lock.release();
|
await lock.release();
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ const InternalCertificateAuthorityConfigurationSchema = z
|
|||||||
organization: z.string().trim(),
|
organization: z.string().trim(),
|
||||||
ou: z.string().trim(),
|
ou: z.string().trim(),
|
||||||
dn: z.string().trim(),
|
dn: z.string().trim(),
|
||||||
parentCaId: z.string().uuid().optional(),
|
parentCaId: z.string().uuid().nullish(),
|
||||||
serialNumber: z.string().trim().optional(),
|
serialNumber: z.string().trim().optional(),
|
||||||
activeCaCertId: z.string().uuid().optional(),
|
activeCaCertId: z.string().uuid().optional(),
|
||||||
country: z.string().trim(),
|
country: z.string().trim(),
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ export const sanitizedPkiSubscriber = PkiSubscribersSchema.pick({
|
|||||||
subjectAlternativeNames: true,
|
subjectAlternativeNames: true,
|
||||||
ttl: true,
|
ttl: true,
|
||||||
keyUsages: true,
|
keyUsages: true,
|
||||||
extendedKeyUsages: true
|
extendedKeyUsages: true,
|
||||||
|
lastOperationStatus: true,
|
||||||
|
lastOperationMessage: true,
|
||||||
|
lastOperationAt: true
|
||||||
}).extend({
|
}).extend({
|
||||||
supportsImmediateCertIssuance: z.boolean().optional()
|
supportsImmediateCertIssuance: z.boolean().optional()
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -56,3 +56,8 @@ export type TListPkiSubscriberCertsDTO = {
|
|||||||
offset: number;
|
offset: number;
|
||||||
limit: number;
|
limit: number;
|
||||||
} & TProjectPermission;
|
} & TProjectPermission;
|
||||||
|
|
||||||
|
export enum SubscriberOperationStatus {
|
||||||
|
SUCCESS = "success",
|
||||||
|
FAILED = "failed"
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,13 +39,16 @@ export const pkiSubscriberKeys = {
|
|||||||
] as const
|
] as const
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGetPkiSubscriber = ({
|
export const useGetPkiSubscriber = (
|
||||||
subscriberName,
|
{
|
||||||
projectId
|
subscriberName,
|
||||||
}: {
|
projectId
|
||||||
subscriberName: string;
|
}: {
|
||||||
projectId: string;
|
subscriberName: string;
|
||||||
}) => {
|
projectId: string;
|
||||||
|
},
|
||||||
|
options?: TReactQueryOptions["options"]
|
||||||
|
) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: pkiSubscriberKeys.getPkiSubscriber({ subscriberName, projectId }),
|
queryKey: pkiSubscriberKeys.getPkiSubscriber({ subscriberName, projectId }),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
@@ -59,7 +62,8 @@ export const useGetPkiSubscriber = ({
|
|||||||
);
|
);
|
||||||
return pkiSubscriber;
|
return pkiSubscriber;
|
||||||
},
|
},
|
||||||
enabled: Boolean(subscriberName) && Boolean(projectId)
|
enabled: Boolean(subscriberName) && Boolean(projectId),
|
||||||
|
...options
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ export enum PkiSubscriberStatus {
|
|||||||
DISABLED = "disabled"
|
DISABLED = "disabled"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum SubscriberOperationStatus {
|
||||||
|
SUCCESS = "success",
|
||||||
|
FAILED = "failed"
|
||||||
|
}
|
||||||
|
|
||||||
export type TPkiSubscriber = {
|
export type TPkiSubscriber = {
|
||||||
id: string;
|
id: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
@@ -17,6 +22,9 @@ export type TPkiSubscriber = {
|
|||||||
keyUsages: CertKeyUsage[];
|
keyUsages: CertKeyUsage[];
|
||||||
extendedKeyUsages: CertExtendedKeyUsage[];
|
extendedKeyUsages: CertExtendedKeyUsage[];
|
||||||
supportsImmediateCertIssuance?: boolean;
|
supportsImmediateCertIssuance?: boolean;
|
||||||
|
lastOperationStatus?: SubscriberOperationStatus;
|
||||||
|
lastOperationMessage?: string;
|
||||||
|
lastOperationAt?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TCreatePkiSubscriberDTO = {
|
export type TCreatePkiSubscriberDTO = {
|
||||||
|
|||||||
+1
-1
@@ -56,7 +56,7 @@ export const PkiSubscriberCertificatesTable = ({ subscriberName, handlePopUpOpen
|
|||||||
limit: perPage
|
limit: perPage
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
refetchInterval: 10 * 1000 // 10 seconds
|
refetchInterval: 5000
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
+36
-6
@@ -5,7 +5,14 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|||||||
|
|
||||||
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 { Button, IconButton, Modal, ModalContent, Tooltip } from "@app/components/v2";
|
import {
|
||||||
|
Button,
|
||||||
|
GenericFieldLabel,
|
||||||
|
IconButton,
|
||||||
|
Modal,
|
||||||
|
ModalContent,
|
||||||
|
Tooltip
|
||||||
|
} from "@app/components/v2";
|
||||||
import {
|
import {
|
||||||
ProjectPermissionPkiSubscriberActions,
|
ProjectPermissionPkiSubscriberActions,
|
||||||
ProjectPermissionSub,
|
ProjectPermissionSub,
|
||||||
@@ -19,6 +26,7 @@ import {
|
|||||||
useOrderPkiSubscriberCert
|
useOrderPkiSubscriberCert
|
||||||
} from "@app/hooks/api";
|
} from "@app/hooks/api";
|
||||||
import { pkiSubscriberStatusToNameMap } from "@app/hooks/api/pkiSubscriber/constants";
|
import { pkiSubscriberStatusToNameMap } from "@app/hooks/api/pkiSubscriber/constants";
|
||||||
|
import { SubscriberOperationStatus } from "@app/hooks/api/pkiSubscriber/types";
|
||||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
import { CertificateContent } from "../../CertificatesPage/components/CertificateContent";
|
import { CertificateContent } from "../../CertificatesPage/components/CertificateContent";
|
||||||
@@ -45,10 +53,15 @@ export const PkiSubscriberDetailsSection = ({ subscriberName, handlePopUpOpen }:
|
|||||||
initialState: "Copy ID to clipboard"
|
initialState: "Copy ID to clipboard"
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: pkiSubscriber } = useGetPkiSubscriber({
|
const { data: pkiSubscriber } = useGetPkiSubscriber(
|
||||||
subscriberName,
|
{
|
||||||
projectId
|
subscriberName,
|
||||||
});
|
projectId
|
||||||
|
},
|
||||||
|
{
|
||||||
|
refetchInterval: 5000
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const { mutateAsync: issuePkiSubscriberCert, isPending: isIssuingCert } =
|
const { mutateAsync: issuePkiSubscriberCert, isPending: isIssuingCert } =
|
||||||
useIssuePkiSubscriberCert();
|
useIssuePkiSubscriberCert();
|
||||||
@@ -163,9 +176,26 @@ export const PkiSubscriberDetailsSection = ({ subscriberName, handlePopUpOpen }:
|
|||||||
<p className="text-sm font-semibold text-mineshaft-300">Common Name</p>
|
<p className="text-sm font-semibold text-mineshaft-300">Common Name</p>
|
||||||
<p className="text-sm text-mineshaft-300">{pkiSubscriber.commonName}</p>
|
<p className="text-sm text-mineshaft-300">{pkiSubscriber.commonName}</p>
|
||||||
</div>
|
</div>
|
||||||
|
{pkiSubscriber.lastOperationAt && (
|
||||||
|
<div className="mb-4">
|
||||||
|
<p className="text-sm font-semibold text-mineshaft-300">Last Operation (Local Time)</p>
|
||||||
|
<p className="text-sm text-mineshaft-300">
|
||||||
|
{new Date(pkiSubscriber.lastOperationAt).toLocaleString()}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{pkiSubscriber.lastOperationStatus === SubscriberOperationStatus.FAILED && (
|
||||||
|
<div className="mb-4">
|
||||||
|
<GenericFieldLabel labelClassName="text-red" label="Last Operation Status">
|
||||||
|
<p className="break-words rounded bg-mineshaft-600 p-2 text-xs">
|
||||||
|
{pkiSubscriber.lastOperationMessage}
|
||||||
|
</p>
|
||||||
|
</GenericFieldLabel>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{canIssuePkiSubscriberCert && (
|
{canIssuePkiSubscriberCert && (
|
||||||
<Button
|
<Button
|
||||||
className="mt-4 w-full"
|
className="mt-2 w-full"
|
||||||
colorSchema="primary"
|
colorSchema="primary"
|
||||||
type="button"
|
type="button"
|
||||||
isLoading={isIssuingCert}
|
isLoading={isIssuingCert}
|
||||||
|
|||||||
Reference in New Issue
Block a user