PKI Syncs revamp

This commit is contained in:
Carlos Monastyrski
2025-10-29 13:01:27 -03:00
parent 3e83ae95d1
commit 39eecb328d
64 changed files with 2799 additions and 350 deletions
@@ -26,7 +26,7 @@ export const registerSyncPkiEndpoints = ({
syncOptions?: Record<string, unknown>;
description?: string;
isAutoSyncEnabled?: boolean;
subscriberId?: string;
subscriberId?: string | null;
}>;
updateSchema: z.ZodType<{
connectionId?: string;
@@ -35,7 +35,7 @@ export const registerSyncPkiEndpoints = ({
syncOptions?: Record<string, unknown>;
description?: string;
isAutoSyncEnabled?: boolean;
subscriberId?: string;
subscriberId?: string | null;
}>;
responseSchema: z.ZodTypeAny;
syncOptions: {
@@ -2,10 +2,11 @@ import { z } from "zod";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ApiDocsTags } from "@app/lib/api-docs";
import { readLimit } from "@app/server/config/rateLimiter";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import { AuthMode } from "@app/services/auth/auth-type";
import { CertificateSyncStatus } from "@app/services/certificate-sync/certificate-sync-enums";
import { PkiSync } from "@app/services/pki-sync/pki-sync-enums";
const PkiSyncSchema = z.object({
@@ -60,7 +61,8 @@ const PkiSyncSchema = z.object({
name: z.string()
})
.nullable()
.optional()
.optional(),
hasCertificate: z.boolean().optional()
});
const PkiSyncOptionsSchema = z.object({
@@ -76,6 +78,24 @@ const PkiSyncOptionsSchema = z.object({
minCertificateNameLength: z.number().optional()
});
const PkiSyncCertificateSchema = z.object({
id: z.string().uuid(),
pkiSyncId: z.string().uuid(),
certificateId: z.string().uuid(),
syncStatus: z.nativeEnum(CertificateSyncStatus),
lastSyncMessage: z.string().nullable().optional(),
lastSyncedAt: z.date().nullable().optional(),
createdAt: z.date(),
updatedAt: z.date(),
certificateSerialNumber: z.string().optional(),
certificateCommonName: z.string().optional(),
certificateStatus: z.string().optional(),
certificateNotBefore: z.date().optional(),
certificateNotAfter: z.date().optional(),
pkiSyncName: z.string().optional(),
pkiSyncDestination: z.string().optional()
});
export const registerPkiSyncRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
@@ -111,7 +131,8 @@ export const registerPkiSyncRouter = async (server: FastifyZodProvider) => {
tags: [ApiDocsTags.PkiSyncs],
description: "List all the PKI Syncs for the specified project.",
querystring: z.object({
projectId: z.string().trim().min(1)
projectId: z.string().trim().min(1),
certificateId: z.string().uuid().optional()
}),
response: {
200: z.object({ pkiSyncs: PkiSyncSchema.array() })
@@ -120,11 +141,11 @@ export const registerPkiSyncRouter = async (server: FastifyZodProvider) => {
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const {
query: { projectId },
query: { projectId, certificateId },
permission
} = req;
const pkiSyncs = await server.services.pkiSync.listPkiSyncsByProjectId({ projectId }, permission);
const pkiSyncs = await server.services.pkiSync.listPkiSyncsByProjectId({ projectId, certificateId }, permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
@@ -179,4 +200,167 @@ export const registerPkiSyncRouter = async (server: FastifyZodProvider) => {
return pkiSync;
}
});
server.route({
method: "GET",
url: "/:pkiSyncId/certificates",
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSyncs],
description: "List all certificates associated with a PKI Sync.",
params: z.object({
pkiSyncId: z.string().uuid()
}),
querystring: z.object({
offset: z.coerce.number().min(0).default(0),
limit: z.coerce.number().min(1).max(100).default(20)
}),
response: {
200: z.object({
certificates: PkiSyncCertificateSchema.array(),
totalCount: z.number()
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { pkiSyncId } = req.params;
const { offset, limit } = req.query;
const result = await server.services.pkiSync.listPkiSyncCertificates(
{ pkiSyncId, offset, limit },
req.permission
);
const pkiSync = await server.services.pkiSync.findPkiSyncById({ id: pkiSyncId }, req.permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: pkiSync.projectId,
event: {
type: EventType.GET_PKI_SYNC,
metadata: {
syncId: pkiSyncId,
destination: pkiSync.destination
}
}
});
return result;
}
});
server.route({
method: "POST",
url: "/:pkiSyncId/certificates",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSyncs],
description: "Add certificates to a PKI Sync.",
params: z.object({
pkiSyncId: z.string().uuid()
}),
body: z.object({
certificateIds: z.array(z.string().uuid()).min(1, "At least one certificate ID is required")
}),
response: {
200: z.object({
addedCertificates: z.array(
z.object({
id: z.string().uuid(),
pkiSyncId: z.string().uuid(),
certificateId: z.string().uuid(),
syncStatus: z.string().default("pending").optional().nullable(),
lastSyncMessage: z.string().optional().nullable(),
lastSyncedAt: z.date().optional().nullable(),
createdAt: z.date(),
updatedAt: z.date()
})
)
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { pkiSyncId } = req.params;
const { certificateIds } = req.body;
const addedCertificates = await server.services.pkiSync.addCertificatesToPkiSync(
{ pkiSyncId, certificateIds },
req.permission
);
const pkiSync = await server.services.pkiSync.findPkiSyncById({ id: pkiSyncId }, req.permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: pkiSync.projectId,
event: {
type: EventType.UPDATE_PKI_SYNC,
metadata: {
pkiSyncId,
name: pkiSync.name
}
}
});
return { addedCertificates };
}
});
server.route({
method: "DELETE",
url: "/:pkiSyncId/certificates",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSyncs],
description: "Remove certificates from a PKI Sync.",
params: z.object({
pkiSyncId: z.string().uuid()
}),
body: z.object({
certificateIds: z.array(z.string().uuid()).min(1, "At least one certificate ID is required")
}),
response: {
200: z.object({
removedCount: z.number()
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { pkiSyncId } = req.params;
const { certificateIds } = req.body;
const result = await server.services.pkiSync.removeCertificatesFromPkiSync(
{ pkiSyncId, certificateIds },
req.permission
);
const pkiSync = await server.services.pkiSync.findPkiSyncById({ id: pkiSyncId }, req.permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: pkiSync.projectId,
event: {
type: EventType.UPDATE_PKI_SYNC,
metadata: {
pkiSyncId,
name: pkiSync.name
}
}
});
return result;
}
});
};
@@ -1195,8 +1195,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
querystring: z.object({
friendlyName: z.string().optional().describe(PROJECTS.LIST_CERTIFICATES.friendlyName),
commonName: z.string().optional().describe(PROJECTS.LIST_CERTIFICATES.commonName),
offset: z.coerce.number().min(0).max(100).default(0).describe(PROJECTS.LIST_CERTIFICATES.offset),
limit: z.coerce.number().min(1).max(100).default(25).describe(PROJECTS.LIST_CERTIFICATES.limit)
offset: z.coerce.number().min(0).default(0).describe(PROJECTS.LIST_CERTIFICATES.offset),
limit: z.coerce.number().min(1).max(100).default(25).describe(PROJECTS.LIST_CERTIFICATES.limit),
forPkiSync: z.coerce
.boolean()
.default(false)
.optional()
.describe("Retrieve only certificates available for PKI sync")
}),
response: {
200: z.object({