Add PKI Syncs docs and a few improvements on the router

This commit is contained in:
Carlos Monastyrski
2025-09-17 10:49:31 -03:00
parent bc04fc6113
commit 8130be5e2f
52 changed files with 1124 additions and 690 deletions
@@ -0,0 +1,17 @@
import {
AzureKeyVaultPkiSyncSchema,
CreateAzureKeyVaultPkiSyncSchema,
UpdateAzureKeyVaultPkiSyncSchema
} from "@app/services/pki-sync/azure-key-vault";
import { PkiSync } from "@app/services/pki-sync/pki-sync-enums";
import { registerSyncPkiEndpoints } from "./pki-sync-endpoints";
export const registerAzureKeyVaultPkiSyncRouter = async (server: FastifyZodProvider) =>
registerSyncPkiEndpoints({
destination: PkiSync.AzureKeyVault,
server,
responseSchema: AzureKeyVaultPkiSyncSchema,
createSchema: CreateAzureKeyVaultPkiSyncSchema,
updateSchema: UpdateAzureKeyVaultPkiSyncSchema
});
@@ -0,0 +1,9 @@
import { PkiSync } from "@app/services/pki-sync/pki-sync-enums";
import { registerAzureKeyVaultPkiSyncRouter } from "./azure-key-vault-pki-sync-router";
export * from "./pki-sync-router";
export const PKI_SYNC_REGISTER_ROUTER_MAP: Record<PkiSync, (server: FastifyZodProvider) => Promise<void>> = {
[PkiSync.AzureKeyVault]: registerAzureKeyVaultPkiSyncRouter
};
@@ -0,0 +1,363 @@
import { z } from "zod";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ApiDocsTags } from "@app/lib/api-docs";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { PkiSync } from "@app/services/pki-sync/pki-sync-enums";
import { PKI_SYNC_NAME_MAP } from "@app/services/pki-sync/pki-sync-maps";
export const registerSyncPkiEndpoints = ({
server,
destination,
createSchema,
updateSchema,
responseSchema
}: {
destination: PkiSync;
server: FastifyZodProvider;
createSchema: z.ZodType<{
name: string;
projectId: string;
connectionId: string;
destinationConfig: Record<string, unknown>;
syncOptions?: Record<string, unknown>;
description?: string;
isAutoSyncEnabled?: boolean;
subscriberId?: string;
}>;
updateSchema: z.ZodType<{
connectionId?: string;
name?: string;
destinationConfig?: Record<string, unknown>;
syncOptions?: Record<string, unknown>;
description?: string;
isAutoSyncEnabled?: boolean;
subscriberId?: string;
}>;
responseSchema: z.ZodTypeAny;
}) => {
const destinationName = PKI_SYNC_NAME_MAP[destination];
server.route({
method: "GET",
url: `/`,
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSyncs],
description: `List the ${destinationName} PKI Syncs for the specified project.`,
querystring: z.object({
projectId: z.string().trim().min(1, "Project ID required")
}),
response: {
200: z.object({ pkiSyncs: responseSchema.array() })
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]),
handler: async (req) => {
const {
query: { projectId }
} = req;
const pkiSyncs = await server.services.pkiSync.listPkiSyncsByProjectId({ projectId }, req.permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId,
event: {
type: EventType.GET_PKI_SYNCS,
metadata: {
projectId
}
}
});
return { pkiSyncs };
}
});
server.route({
method: "GET",
url: "/:pkiSyncId",
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSyncs],
description: `Get the specified ${destinationName} PKI Sync by ID.`,
params: z.object({
pkiSyncId: z.string()
}),
querystring: z.object({
projectId: z.string().trim().min(1)
}),
response: {
200: z.object({ pkiSync: responseSchema })
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]),
handler: async (req) => {
const { pkiSyncId } = req.params;
const { projectId } = req.query;
const pkiSync = await server.services.pkiSync.findPkiSyncById({ id: pkiSyncId, projectId }, req.permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: pkiSync.projectId,
event: {
type: EventType.GET_PKI_SYNC,
metadata: {
syncId: pkiSyncId,
destination
}
}
});
return { pkiSync };
}
});
server.route({
method: "POST",
url: "/",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSyncs],
description: `Create a ${destinationName} PKI Sync for the specified project.`,
body: createSchema,
response: {
200: z.object({ pkiSync: responseSchema })
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]),
handler: async (req) => {
const pkiSync = await server.services.pkiSync.createPkiSync({ ...req.body, destination }, req.permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: pkiSync.projectId,
event: {
type: EventType.CREATE_PKI_SYNC,
metadata: {
pkiSyncId: pkiSync.id,
name: pkiSync.name,
destination
}
}
});
return { pkiSync };
}
});
server.route({
method: "PATCH",
url: "/:pkiSyncId",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSyncs],
description: `Update the specified ${destinationName} PKI Sync.`,
params: z.object({
pkiSyncId: z.string()
}),
querystring: z.object({
projectId: z.string().trim().min(1)
}),
body: updateSchema,
response: {
200: z.object({ pkiSync: responseSchema })
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]),
handler: async (req) => {
const { pkiSyncId } = req.params;
const { projectId } = req.query;
const pkiSync = await server.services.pkiSync.updatePkiSync(
{ ...req.body, id: pkiSyncId, projectId },
req.permission
);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId,
event: {
type: EventType.UPDATE_PKI_SYNC,
metadata: {
pkiSyncId,
name: pkiSync.name
}
}
});
return { pkiSync };
}
});
server.route({
method: "DELETE",
url: `/:pkiSyncId`,
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSyncs],
description: `Delete the specified ${destinationName} PKI Sync.`,
params: z.object({
pkiSyncId: z.string()
}),
querystring: z.object({
projectId: z.string().trim().min(1)
}),
response: {
200: z.object({ pkiSync: responseSchema })
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]),
handler: async (req) => {
const { pkiSyncId } = req.params;
const { projectId } = req.query;
const pkiSync = await server.services.pkiSync.deletePkiSync({ id: pkiSyncId, projectId }, req.permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId,
event: {
type: EventType.DELETE_PKI_SYNC,
metadata: {
pkiSyncId,
name: pkiSync.name,
destination: pkiSync.destination
}
}
});
return { pkiSync };
}
});
server.route({
method: "POST",
url: "/:pkiSyncId/sync",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSyncs],
description: `Trigger a sync for the specified ${destinationName} PKI Sync.`,
params: z.object({
pkiSyncId: z.string()
}),
querystring: z.object({
projectId: z.string().trim().min(1)
}),
response: {
200: z.object({ message: z.string() })
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]),
handler: async (req) => {
const { pkiSyncId } = req.params;
const { projectId } = req.query;
const result = await server.services.pkiSync.triggerPkiSyncSyncCertificatesById(
{
id: pkiSyncId,
projectId
},
req.permission
);
return result;
}
});
server.route({
method: "POST",
url: "/:pkiSyncId/import",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSyncs],
description: `Import certificates from the specified ${destinationName} PKI Sync destination.`,
params: z.object({
pkiSyncId: z.string()
}),
querystring: z.object({
projectId: z.string().trim().min(1)
}),
response: {
200: z.object({ message: z.string() })
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]),
handler: async (req) => {
const { pkiSyncId } = req.params;
const { projectId } = req.query;
const result = await server.services.pkiSync.triggerPkiSyncImportCertificatesById(
{
id: pkiSyncId,
projectId
},
req.permission
);
return result;
}
});
server.route({
method: "POST",
url: "/:pkiSyncId/remove",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSyncs],
description: `Remove certificates from the specified ${destinationName} PKI Sync destination.`,
params: z.object({
pkiSyncId: z.string()
}),
querystring: z.object({
projectId: z.string().trim().min(1)
}),
response: {
200: z.object({ message: z.string() })
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]),
handler: async (req) => {
const { pkiSyncId } = req.params;
const { projectId } = req.query;
const result = await server.services.pkiSync.triggerPkiSyncRemoveCertificatesById(
{
id: pkiSyncId,
projectId
},
req.permission
);
return result;
}
});
};
@@ -0,0 +1,174 @@
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 { 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 { PkiSync } from "@app/services/pki-sync/pki-sync-enums";
const PkiSyncSchema = z.object({
id: z.string().uuid(),
name: z.string(),
description: z.string().nullable().optional(),
destination: z.nativeEnum(PkiSync),
isAutoSyncEnabled: z.boolean(),
destinationConfig: z.record(z.unknown()),
syncOptions: z.record(z.unknown()),
projectId: z.string().uuid(),
subscriberId: z.string().uuid().nullable().optional(),
connectionId: z.string().uuid(),
createdAt: z.date(),
updatedAt: z.date(),
// Sync status fields
syncStatus: z.string().nullable().optional(),
lastSyncJobId: z.string().nullable().optional(),
lastSyncMessage: z.string().nullable().optional(),
lastSyncedAt: z.date().nullable().optional(),
// Import status fields
importStatus: z.string().nullable().optional(),
lastImportJobId: z.string().nullable().optional(),
lastImportMessage: z.string().nullable().optional(),
lastImportedAt: z.date().nullable().optional(),
// Remove status fields
removeStatus: z.string().nullable().optional(),
lastRemoveJobId: z.string().nullable().optional(),
lastRemoveMessage: z.string().nullable().optional(),
lastRemovedAt: z.date().nullable().optional(),
// App connection info
appConnectionName: z.string(),
appConnectionApp: z.string(),
connection: z.object({
id: z.string(),
name: z.string(),
app: z.string(),
encryptedCredentials: z.unknown().nullable(),
orgId: z.string().uuid(),
projectId: z.string().uuid().nullable().optional(),
method: z.string(),
description: z.string().nullable().optional(),
version: z.number(),
gatewayId: z.string().uuid().nullable().optional(),
createdAt: z.date(),
updatedAt: z.date(),
isPlatformManagedCredentials: z.boolean().nullable().optional()
})
});
const PkiSyncOptionsSchema = z.object({
name: z.string(),
connection: z.nativeEnum(AppConnection),
destination: z.nativeEnum(PkiSync),
canImportCertificates: z.boolean(),
canRemoveCertificates: z.boolean()
});
export const registerPkiSyncRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/options",
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSyncs],
description: "List the available PKI Sync Options.",
response: {
200: z.object({
pkiSyncOptions: PkiSyncOptionsSchema.array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]),
handler: () => {
const pkiSyncOptions = server.services.pkiSync.getPkiSyncOptions();
return { pkiSyncOptions };
}
});
server.route({
method: "GET",
url: "/",
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSyncs],
description: "List all the PKI Syncs for the specified project.",
querystring: z.object({
projectId: z.string().trim().min(1)
}),
response: {
200: z.object({ pkiSyncs: PkiSyncSchema.array() })
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]),
handler: async (req) => {
const {
query: { projectId },
permission
} = req;
const pkiSyncs = await server.services.pkiSync.listPkiSyncsByProjectId({ projectId }, permission);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId,
event: {
type: EventType.GET_PKI_SYNCS,
metadata: {
projectId
}
}
});
return { pkiSyncs };
}
});
server.route({
method: "GET",
url: "/:pkiSyncId",
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSyncs],
description: "Get a PKI Sync by ID.",
params: z.object({
pkiSyncId: z.string()
}),
querystring: z.object({
projectId: z.string().trim().min(1)
}),
response: {
200: z.object({ pkiSync: PkiSyncSchema })
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]),
handler: async (req) => {
const { pkiSyncId } = req.params;
const { projectId } = req.query;
const pkiSync = await server.services.pkiSync.findPkiSyncById({ id: pkiSyncId, projectId }, 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 { pkiSync };
}
});
};