misc: finalized descriptions and api reference

This commit is contained in:
Sheen Capadngan
2025-05-18 22:22:00 +08:00
parent e0f1311f6d
commit 10ed6f6b52
12 changed files with 123 additions and 38 deletions

View File

@@ -5,6 +5,8 @@ import {
} from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-maps";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import { APP_CONNECTION_NAME_MAP } from "@app/services/app-connection/app-connection-maps";
import { CaType } from "@app/services/certificate-authority/certificate-authority-enums";
import { CERTIFICATE_AUTHORITIES_TYPE_MAP } from "@app/services/certificate-authority/certificate-authority-maps";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { SECRET_SYNC_CONNECTION_MAP, SECRET_SYNC_NAME_MAP } from "@app/services/secret-sync/secret-sync-maps";
@@ -1966,6 +1968,46 @@ export const ProjectTemplates = {
}
};
export const CertificateAuthorities = {
CREATE: (type: CaType) => ({
name: `The name of the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority to create. Must be slug-friendly.`,
projectId: `The ID of the project to create the Certificate Authority in.`,
disableDirectIssuance: `Whether or not to disable direct issuance of certificates for the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority.`,
status: `The status of the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority.`
}),
UPDATE: (type: CaType) => ({
caId: `The ID of the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority to update.`,
name: `The updated name of the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority. Must be slug-friendly.`,
disableDirectIssuance: `Whether or not to disable direct issuance of certificates for the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority.`,
status: `The updated status of the ${CERTIFICATE_AUTHORITIES_TYPE_MAP[type]} Certificate Authority.`
}),
CONFIGURATIONS: {
ACME: {
dnsAppConnectionId: `The ID of the App Connection to use for creating and managing DNS TXT records required for ACME domain validation. This connection must have permissions to create and delete TXT records in your DNS provider (e.g., Route53) for the ACME challenge process.`,
directoryUrl: `The directory URL for the ACME Certificate Authority.`,
accountEmail: `The email address for the ACME Certificate Authority.`,
provider: `The DNS provider for the ACME Certificate Authority.`,
hostedZoneId: `The hosted zone ID for the ACME Certificate Authority.`
},
INTERNAL: {
type: "The type of CA to create.",
friendlyName: "A friendly name for the CA.",
organization: "The organization (O) for the CA.",
ou: "The organization unit (OU) for the CA.",
country: "The country name (C) for the CA.",
province: "The state of province name for the CA.",
locality: "The locality name for the CA.",
commonName: "The common name (CN) for the CA.",
notBefore: "The date and time when the CA becomes valid in YYYY-MM-DDTHH:mm:ss.sssZ format.",
notAfter: "The date and time when the CA expires in YYYY-MM-DDTHH:mm:ss.sssZ format.",
maxPathLength:
"The maximum number of intermediate CAs that may follow this CA in the certificate / CA chain. A maxPathLength of -1 implies no path limit on the chain.",
keyAlgorithm:
"The type of public key algorithm and size, in bits, of the key pair for the CA; when you create an intermediate CA, you must use a key algorithm supported by the parent CA."
}
}
};
export const AppConnections = {
GET_BY_ID: (app: AppConnection) => ({
connectionId: `The ID of the ${APP_CONNECTION_NAME_MAP[app]} Connection to retrieve.`

View File

@@ -1,5 +1,7 @@
import { z } from "zod";
import { CertificateAuthorities } from "@app/lib/api-docs/constants";
import { CaType } from "../certificate-authority-enums";
import {
BaseCertificateAuthoritySchema,
@@ -9,21 +11,21 @@ import {
import { AcmeDnsProvider } from "./acme-certificate-authority-enums";
export const AcmeCertificateAuthorityConfigurationSchema = z.object({
dnsAppConnectionId: z.string().trim(),
dnsAppConnectionId: z.string().trim().describe(CertificateAuthorities.CONFIGURATIONS.ACME.dnsAppConnectionId),
// soon, differentiate via the provider property
dnsProviderConfig: z.object({
provider: z.nativeEnum(AcmeDnsProvider),
hostedZoneId: z.string().trim().min(1)
provider: z.nativeEnum(AcmeDnsProvider).describe(CertificateAuthorities.CONFIGURATIONS.ACME.provider),
hostedZoneId: z.string().trim().min(1).describe(CertificateAuthorities.CONFIGURATIONS.ACME.hostedZoneId)
}),
directoryUrl: z.string().trim().min(1),
accountEmail: z.string().trim().min(1)
directoryUrl: z.string().trim().min(1).describe(CertificateAuthorities.CONFIGURATIONS.ACME.directoryUrl),
accountEmail: z.string().trim().min(1).describe(CertificateAuthorities.CONFIGURATIONS.ACME.accountEmail)
});
export const AcmeCertificateAuthorityCredentialsSchema = z.object({
accountKey: z.string()
});
export const AcmeCertificateAuthoritySchema = BaseCertificateAuthoritySchema(CaType.ACME).extend({
export const AcmeCertificateAuthoritySchema = BaseCertificateAuthoritySchema.extend({
type: z.literal(CaType.ACME),
configuration: AcmeCertificateAuthorityConfigurationSchema
});

View File

@@ -0,0 +1,6 @@
import { CaType } from "./certificate-authority-enums";
export const CERTIFICATE_AUTHORITIES_TYPE_MAP: Record<CaType, string> = {
[CaType.INTERNAL]: "Internal",
[CaType.ACME]: "ACME"
};

View File

@@ -1,32 +1,31 @@
import z from "zod";
import { CertificateAuthoritiesSchema } from "@app/db/schemas";
import { CertificateAuthorities } from "@app/lib/api-docs/constants";
import { slugSchema } from "@app/server/lib/schemas";
import { CaStatus, CaType } from "./certificate-authority-enums";
// SHEEN TODO: add description mapping using type
export const BaseCertificateAuthoritySchema = (type: CaType) =>
CertificateAuthoritiesSchema.pick({
projectId: true,
disableDirectIssuance: true,
id: true
}).extend({
name: z.string(),
status: z.nativeEnum(CaStatus)
});
export const BaseCertificateAuthoritySchema = CertificateAuthoritiesSchema.pick({
projectId: true,
disableDirectIssuance: true,
id: true
}).extend({
name: z.string(),
status: z.nativeEnum(CaStatus)
});
export const GenericCreateCertificateAuthorityFieldsSchema = (type: CaType) =>
z.object({
name: slugSchema({ field: "name" }),
projectId: z.string().trim().min(1, "Project ID required"),
disableDirectIssuance: z.boolean(),
status: z.nativeEnum(CaStatus)
name: slugSchema({ field: "name" }).describe(CertificateAuthorities.CREATE(type).name),
projectId: z.string().trim().min(1, "Project ID required").describe(CertificateAuthorities.CREATE(type).projectId),
disableDirectIssuance: z.boolean().describe(CertificateAuthorities.CREATE(type).disableDirectIssuance),
status: z.nativeEnum(CaStatus).describe(CertificateAuthorities.CREATE(type).status)
});
export const GenericUpdateCertificateAuthorityFieldsSchema = (type: CaType) =>
z.object({
name: slugSchema({ field: "name" }).optional(),
disableDirectIssuance: z.boolean().optional(),
status: z.nativeEnum(CaStatus).optional()
name: slugSchema({ field: "name" }).optional().describe(CertificateAuthorities.UPDATE(type).name),
disableDirectIssuance: z.boolean().optional().describe(CertificateAuthorities.UPDATE(type).disableDirectIssuance),
status: z.nativeEnum(CaStatus).optional().describe(CertificateAuthorities.UPDATE(type).status)
});

View File

@@ -1,5 +1,6 @@
import { z } from "zod";
import { CertificateAuthorities } from "@app/lib/api-docs/constants";
import { CertKeyAlgorithm } from "@app/services/certificate/certificate-types";
import { CaType, InternalCaType } from "../certificate-authority-enums";
@@ -12,22 +13,24 @@ import { validateCaDateField } from "../certificate-authority-validators";
const InternalCertificateAuthorityConfigurationSchema = z
.object({
type: z.nativeEnum(InternalCaType),
friendlyName: z.string().optional(),
commonName: z.string().trim(),
organization: z.string().trim(),
ou: z.string().trim(),
type: z.nativeEnum(InternalCaType).describe(CertificateAuthorities.CONFIGURATIONS.INTERNAL.type),
friendlyName: z.string().optional().describe(CertificateAuthorities.CONFIGURATIONS.INTERNAL.friendlyName),
commonName: z.string().trim().describe(CertificateAuthorities.CONFIGURATIONS.INTERNAL.commonName),
organization: z.string().trim().describe(CertificateAuthorities.CONFIGURATIONS.INTERNAL.organization),
ou: z.string().trim().describe(CertificateAuthorities.CONFIGURATIONS.INTERNAL.ou),
country: z.string().trim().describe(CertificateAuthorities.CONFIGURATIONS.INTERNAL.country),
province: z.string().trim().describe(CertificateAuthorities.CONFIGURATIONS.INTERNAL.province),
locality: z.string().trim().describe(CertificateAuthorities.CONFIGURATIONS.INTERNAL.locality),
notBefore: validateCaDateField.optional().describe(CertificateAuthorities.CONFIGURATIONS.INTERNAL.notBefore),
notAfter: validateCaDateField.optional().describe(CertificateAuthorities.CONFIGURATIONS.INTERNAL.notAfter),
maxPathLength: z.number().min(-1).describe(CertificateAuthorities.CONFIGURATIONS.INTERNAL.maxPathLength),
keyAlgorithm: z.nativeEnum(CertKeyAlgorithm).describe(CertificateAuthorities.CONFIGURATIONS.INTERNAL.keyAlgorithm),
// no need for descriptions of the following fields because they are not exposed to the API user
dn: z.string().trim(),
parentCaId: z.string().uuid().nullish(),
serialNumber: z.string().trim().optional(),
activeCaCertId: z.string().uuid().optional(),
country: z.string().trim(),
province: z.string().trim(),
locality: z.string().trim(),
notBefore: validateCaDateField.optional(),
notAfter: validateCaDateField.optional(),
maxPathLength: z.number().min(-1),
keyAlgorithm: z.nativeEnum(CertKeyAlgorithm)
activeCaCertId: z.string().uuid().optional()
})
.refine(
(data) => {
@@ -43,7 +46,7 @@ const InternalCertificateAuthorityConfigurationSchema = z
}
);
export const InternalCertificateAuthoritySchema = BaseCertificateAuthoritySchema(CaType.INTERNAL).extend({
export const InternalCertificateAuthoritySchema = BaseCertificateAuthoritySchema.extend({
type: z.literal(CaType.INTERNAL),
configuration: InternalCertificateAuthorityConfigurationSchema
});

View File

@@ -0,0 +1,4 @@
---
title: "Create"
openapi: "POST /api/v1/pki/ca/acme"
---

View File

@@ -0,0 +1,4 @@
---
title: "Delete"
openapi: "DELETE /api/v1/pki/ca/acme/{caId}"
---

View File

@@ -0,0 +1,4 @@
---
title: "Get By ID"
openapi: "GET /api/v1/pki/ca/acme/{caId}"
---

View File

@@ -0,0 +1,4 @@
---
title: "List"
openapi: "GET /api/v1/pki/ca/acme"
---

View File

@@ -0,0 +1,4 @@
---
title: "Update"
openapi: "PATCH /api/v1/pki/ca/acme/{caId}"
---

View File

@@ -1474,6 +1474,16 @@
{
"group": "Certificate Authorities",
"pages": [
{
"group": "ACME",
"pages": [
"api-reference/endpoints/certificate-authorities/acme/list",
"api-reference/endpoints/certificate-authorities/acme/create",
"api-reference/endpoints/certificate-authorities/acme/read",
"api-reference/endpoints/certificate-authorities/acme/update",
"api-reference/endpoints/certificate-authorities/acme/delete"
]
},
"api-reference/endpoints/certificate-authorities/list",
"api-reference/endpoints/certificate-authorities/create",
"api-reference/endpoints/certificate-authorities/read",

View File

@@ -27,11 +27,14 @@ import {
useUpdateUnifiedCa
} from "@app/hooks/api/ca";
import { UsePopUpState } from "@app/hooks/usePopUp";
import { slugSchema } from "@app/lib/schemas";
const schema = z
.object({
type: z.nativeEnum(CaType),
name: z.string(),
name: slugSchema({
field: "Name"
}),
disableDirectIssuance: z.boolean(),
status: z.nativeEnum(CaStatus),
configuration: z.object({