@zuplo/cli 6.70.14 → 6.70.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/ca-certificate/create/handler.d.ts +3 -0
  2. package/dist/ca-certificate/create/handler.d.ts.map +1 -0
  3. package/dist/ca-certificate/create/handler.js +46 -0
  4. package/dist/ca-certificate/create/handler.js.map +1 -0
  5. package/dist/ca-certificate/delete/handler.d.ts +3 -0
  6. package/dist/ca-certificate/delete/handler.d.ts.map +1 -0
  7. package/dist/ca-certificate/delete/handler.js +18 -0
  8. package/dist/ca-certificate/delete/handler.js.map +1 -0
  9. package/dist/ca-certificate/describe/handler.d.ts +3 -0
  10. package/dist/ca-certificate/describe/handler.d.ts.map +1 -0
  11. package/dist/ca-certificate/describe/handler.js +32 -0
  12. package/dist/ca-certificate/describe/handler.js.map +1 -0
  13. package/dist/ca-certificate/list/handler.d.ts +3 -0
  14. package/dist/ca-certificate/list/handler.d.ts.map +1 -0
  15. package/dist/ca-certificate/list/handler.js +28 -0
  16. package/dist/ca-certificate/list/handler.js.map +1 -0
  17. package/dist/ca-certificate/models.d.ts +51 -0
  18. package/dist/ca-certificate/models.d.ts.map +1 -0
  19. package/dist/ca-certificate/models.js +2 -0
  20. package/dist/ca-certificate/models.js.map +1 -0
  21. package/dist/ca-certificate/update/handler.d.ts +3 -0
  22. package/dist/ca-certificate/update/handler.d.ts.map +1 -0
  23. package/dist/ca-certificate/update/handler.js +26 -0
  24. package/dist/ca-certificate/update/handler.js.map +1 -0
  25. package/dist/ca-certificate/validation.d.ts +21 -0
  26. package/dist/ca-certificate/validation.d.ts.map +1 -0
  27. package/dist/ca-certificate/validation.js +135 -0
  28. package/dist/ca-certificate/validation.js.map +1 -0
  29. package/dist/ca-certificate/validation.test.d.ts +2 -0
  30. package/dist/ca-certificate/validation.test.d.ts.map +1 -0
  31. package/dist/ca-certificate/validation.test.js +131 -0
  32. package/dist/ca-certificate/validation.test.js.map +1 -0
  33. package/dist/cli.js +2 -0
  34. package/dist/cli.js.map +1 -1
  35. package/dist/cmds/ca-certificate/create.d.ts +9 -0
  36. package/dist/cmds/ca-certificate/create.d.ts.map +1 -0
  37. package/dist/cmds/ca-certificate/create.js +66 -0
  38. package/dist/cmds/ca-certificate/create.js.map +1 -0
  39. package/dist/cmds/ca-certificate/delete.d.ts +9 -0
  40. package/dist/cmds/ca-certificate/delete.d.ts.map +1 -0
  41. package/dist/cmds/ca-certificate/delete.js +56 -0
  42. package/dist/cmds/ca-certificate/delete.js.map +1 -0
  43. package/dist/cmds/ca-certificate/describe.d.ts +9 -0
  44. package/dist/cmds/ca-certificate/describe.d.ts.map +1 -0
  45. package/dist/cmds/ca-certificate/describe.js +56 -0
  46. package/dist/cmds/ca-certificate/describe.js.map +1 -0
  47. package/dist/cmds/ca-certificate/index.d.ts +4 -0
  48. package/dist/cmds/ca-certificate/index.d.ts.map +1 -0
  49. package/dist/cmds/ca-certificate/index.js +18 -0
  50. package/dist/cmds/ca-certificate/index.js.map +1 -0
  51. package/dist/cmds/ca-certificate/list.d.ts +9 -0
  52. package/dist/cmds/ca-certificate/list.d.ts.map +1 -0
  53. package/dist/cmds/ca-certificate/list.js +48 -0
  54. package/dist/cmds/ca-certificate/list.js.map +1 -0
  55. package/dist/cmds/ca-certificate/update.d.ts +9 -0
  56. package/dist/cmds/ca-certificate/update.d.ts.map +1 -0
  57. package/dist/cmds/ca-certificate/update.js +56 -0
  58. package/dist/cmds/ca-certificate/update.js.map +1 -0
  59. package/dist/cmds/mtls-certificates/index.js +1 -1
  60. package/dist/cmds/mtls-certificates/index.js.map +1 -1
  61. package/dist/tsconfig.tsbuildinfo +1 -1
  62. package/node_modules/@zuplo/core/package.json +1 -1
  63. package/node_modules/@zuplo/graphql/package.json +1 -1
  64. package/node_modules/@zuplo/openapi-tools/package.json +1 -1
  65. package/node_modules/@zuplo/otel/package.json +1 -1
  66. package/node_modules/@zuplo/runtime/package.json +1 -1
  67. package/package.json +6 -6
@@ -0,0 +1,3 @@
1
+ import { CreateArguments } from "../models.js";
2
+ export declare function create(argv: CreateArguments): Promise<void>;
3
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/ca-certificate/create/handler.ts"],"names":[],"mappings":"AAQA,OAAO,EAAiB,eAAe,EAAE,MAAM,cAAc,CAAC;AAO9D,wBAAsB,MAAM,CAAC,IAAI,EAAE,eAAe,iBAwDjD"}
@@ -0,0 +1,46 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { createApiClient } from "../../common/api/client.js";
3
+ import { logger } from "../../common/logger.js";
4
+ import { printDiagnosticsToConsole, printJsonToConsoleAndExitGracefully, printResultToConsole, } from "../../common/output.js";
5
+ import { isValidationError, parseAndValidateCaCertificate, validateName, } from "../validation.js";
6
+ export async function create(argv) {
7
+ const { account } = argv;
8
+ const nameError = validateName(argv.name);
9
+ if (nameError) {
10
+ printDiagnosticsToConsole(`Error: --name is invalid. ${nameError.message}`);
11
+ return;
12
+ }
13
+ let certificate;
14
+ try {
15
+ certificate = readFileSync(argv.cert, "utf-8");
16
+ }
17
+ catch (error) {
18
+ logger.error(error, "Failed to read CA certificate file");
19
+ printDiagnosticsToConsole(`Error: Failed to read CA certificate file at ${argv.cert}`, error instanceof Error ? error.message : String(error));
20
+ return;
21
+ }
22
+ const parsed = parseAndValidateCaCertificate(certificate);
23
+ if (isValidationError(parsed)) {
24
+ printDiagnosticsToConsole(`Error: ${argv.cert} is not a valid CA certificate. ${parsed.message}`, parsed.hint);
25
+ return;
26
+ }
27
+ const client = createApiClient({ authToken: argv.authToken });
28
+ const cert = await client.post(`/v1/accounts/${account}/client-mtls-ca-certificates`, {
29
+ operation: "Failed to create CA certificate",
30
+ errorMessage: "Error: Failed to create CA certificate. Check the arguments.",
31
+ body: {
32
+ name: argv.name,
33
+ certificate,
34
+ },
35
+ });
36
+ if (argv.output === "json") {
37
+ await printJsonToConsoleAndExitGracefully(cert);
38
+ return;
39
+ }
40
+ const subject = cert.certificateInfo.subject.replace(/\n/g, ", ");
41
+ printResultToConsole(`CA certificate '${cert.name}' (${cert.id}) created successfully\n` +
42
+ ` Subject: ${subject}\n` +
43
+ ` Valid from: ${cert.certificateInfo.validFrom}\n` +
44
+ ` Valid to: ${cert.certificateInfo.validTo}`);
45
+ }
46
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/ca-certificate/create/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EACL,yBAAyB,EACzB,mCAAmC,EACnC,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,iBAAiB,EACjB,6BAA6B,EAC7B,YAAY,GACb,MAAM,kBAAkB,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAqB;IAChD,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAEzB,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,SAAS,EAAE,CAAC;QACd,yBAAyB,CAAC,6BAA6B,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5E,OAAO;IACT,CAAC;IAED,IAAI,WAAmB,CAAC;IACxB,IAAI,CAAC;QACH,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,oCAAoC,CAAC,CAAC;QAC1D,yBAAyB,CACvB,gDAAgD,IAAI,CAAC,IAAI,EAAE,EAC3D,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,6BAA6B,CAAC,WAAW,CAAC,CAAC;IAC1D,IAAI,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9B,yBAAyB,CACvB,UAAU,IAAI,CAAC,IAAI,mCAAmC,MAAM,CAAC,OAAO,EAAE,EACtE,MAAM,CAAC,IAAI,CACZ,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAC5B,gBAAgB,OAAO,8BAA8B,EACrD;QACE,SAAS,EAAE,iCAAiC;QAC5C,YAAY,EACV,8DAA8D;QAChE,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW;SACZ;KACF,CACF,CAAC;IAEF,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC3B,MAAM,mCAAmC,CAAC,IAAI,CAAC,CAAC;QAChD,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAClE,oBAAoB,CAClB,mBAAmB,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,0BAA0B;QACjE,cAAc,OAAO,IAAI;QACzB,iBAAiB,IAAI,CAAC,eAAe,CAAC,SAAS,IAAI;QACnD,eAAe,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,CAChD,CAAC;AACJ,CAAC","sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { createApiClient } from \"../../common/api/client.js\";\nimport { logger } from \"../../common/logger.js\";\nimport {\n printDiagnosticsToConsole,\n printJsonToConsoleAndExitGracefully,\n printResultToConsole,\n} from \"../../common/output.js\";\nimport { CaCertificate, CreateArguments } from \"../models.js\";\nimport {\n isValidationError,\n parseAndValidateCaCertificate,\n validateName,\n} from \"../validation.js\";\n\nexport async function create(argv: CreateArguments) {\n const { account } = argv;\n\n const nameError = validateName(argv.name);\n if (nameError) {\n printDiagnosticsToConsole(`Error: --name is invalid. ${nameError.message}`);\n return;\n }\n\n let certificate: string;\n try {\n certificate = readFileSync(argv.cert, \"utf-8\");\n } catch (error) {\n logger.error(error, \"Failed to read CA certificate file\");\n printDiagnosticsToConsole(\n `Error: Failed to read CA certificate file at ${argv.cert}`,\n error instanceof Error ? error.message : String(error)\n );\n return;\n }\n\n const parsed = parseAndValidateCaCertificate(certificate);\n if (isValidationError(parsed)) {\n printDiagnosticsToConsole(\n `Error: ${argv.cert} is not a valid CA certificate. ${parsed.message}`,\n parsed.hint\n );\n return;\n }\n\n const client = createApiClient({ authToken: argv.authToken });\n const cert = await client.post<CaCertificate>(\n `/v1/accounts/${account}/client-mtls-ca-certificates`,\n {\n operation: \"Failed to create CA certificate\",\n errorMessage:\n \"Error: Failed to create CA certificate. Check the arguments.\",\n body: {\n name: argv.name,\n certificate,\n },\n }\n );\n\n if (argv.output === \"json\") {\n await printJsonToConsoleAndExitGracefully(cert);\n return;\n }\n\n const subject = cert.certificateInfo.subject.replace(/\\n/g, \", \");\n printResultToConsole(\n `CA certificate '${cert.name}' (${cert.id}) created successfully\\n` +\n ` Subject: ${subject}\\n` +\n ` Valid from: ${cert.certificateInfo.validFrom}\\n` +\n ` Valid to: ${cert.certificateInfo.validTo}`\n );\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { DeleteArguments } from "../models.js";
2
+ export declare function deleteCommand(argv: DeleteArguments): Promise<void>;
3
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/ca-certificate/delete/handler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,wBAAsB,aAAa,CAAC,IAAI,EAAE,eAAe,iBAoBxD"}
@@ -0,0 +1,18 @@
1
+ import { createApiClient } from "../../common/api/client.js";
2
+ import { printJsonToConsoleAndExitGracefully, printResultToConsole, } from "../../common/output.js";
3
+ export async function deleteCommand(argv) {
4
+ const { account } = argv;
5
+ const certId = argv["cert-id"];
6
+ const client = createApiClient({ authToken: argv.authToken });
7
+ await client.delete(`/v1/accounts/${account}/client-mtls-ca-certificates/${encodeURIComponent(certId)}`, {
8
+ operation: "Failed to delete CA certificate",
9
+ errorMessage: "Error: Failed to delete CA certificate.",
10
+ emptyResponse: true,
11
+ });
12
+ if (argv.output === "json") {
13
+ await printJsonToConsoleAndExitGracefully({ id: certId, deleted: true });
14
+ return;
15
+ }
16
+ printResultToConsole(`CA certificate ${certId} deleted successfully`);
17
+ }
18
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/ca-certificate/delete/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EACL,mCAAmC,EACnC,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAGhC,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAqB;IACvD,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACzB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;IAE/B,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAC9D,MAAM,MAAM,CAAC,MAAM,CACjB,gBAAgB,OAAO,gCAAgC,kBAAkB,CAAC,MAAM,CAAC,EAAE,EACnF;QACE,SAAS,EAAE,iCAAiC;QAC5C,YAAY,EAAE,yCAAyC;QACvD,aAAa,EAAE,IAAI;KACpB,CACF,CAAC;IAEF,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC3B,MAAM,mCAAmC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACzE,OAAO;IACT,CAAC;IAED,oBAAoB,CAAC,kBAAkB,MAAM,uBAAuB,CAAC,CAAC;AACxE,CAAC","sourcesContent":["import { createApiClient } from \"../../common/api/client.js\";\nimport {\n printJsonToConsoleAndExitGracefully,\n printResultToConsole,\n} from \"../../common/output.js\";\nimport { DeleteArguments } from \"../models.js\";\n\nexport async function deleteCommand(argv: DeleteArguments) {\n const { account } = argv;\n const certId = argv[\"cert-id\"];\n\n const client = createApiClient({ authToken: argv.authToken });\n await client.delete(\n `/v1/accounts/${account}/client-mtls-ca-certificates/${encodeURIComponent(certId)}`,\n {\n operation: \"Failed to delete CA certificate\",\n errorMessage: \"Error: Failed to delete CA certificate.\",\n emptyResponse: true,\n }\n );\n\n if (argv.output === \"json\") {\n await printJsonToConsoleAndExitGracefully({ id: certId, deleted: true });\n return;\n }\n\n printResultToConsole(`CA certificate ${certId} deleted successfully`);\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { DescribeArguments } from "../models.js";
2
+ export declare function describe(argv: DescribeArguments): Promise<void>;
3
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/ca-certificate/describe/handler.ts"],"names":[],"mappings":"AAMA,OAAO,EAA6B,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAK5E,wBAAsB,QAAQ,CAAC,IAAI,EAAE,iBAAiB,iBAuCrD"}
@@ -0,0 +1,32 @@
1
+ import { createApiClient } from "../../common/api/client.js";
2
+ import { printDiagnosticsToConsole, printJsonToConsoleAndExitGracefully, printResultToConsole, } from "../../common/output.js";
3
+ export async function describe(argv) {
4
+ const { account } = argv;
5
+ const certId = argv["cert-id"];
6
+ const client = createApiClient({ authToken: argv.authToken });
7
+ const response = await client.get(`/v1/accounts/${account}/client-mtls-ca-certificates`, {
8
+ operation: "Failed to describe CA certificate",
9
+ errorMessage: "Error: Failed to describe CA certificate.",
10
+ });
11
+ const cert = response.data.find((c) => c.id === certId);
12
+ if (!cert) {
13
+ printDiagnosticsToConsole(`Error: CA certificate with ID '${certId}' not found in account '${account}'`);
14
+ return;
15
+ }
16
+ if (argv.output === "json") {
17
+ await printJsonToConsoleAndExitGracefully(cert);
18
+ return;
19
+ }
20
+ const subject = cert.certificateInfo.subject.replace(/\n/g, ", ");
21
+ const issuer = cert.certificateInfo.issuer.replace(/\n/g, ", ");
22
+ printResultToConsole(` ID: ${cert.id}\n` +
23
+ ` Name: ${cert.name}\n` +
24
+ ` Subject: ${subject}\n` +
25
+ ` Issuer: ${issuer}\n` +
26
+ ` Serial: ${cert.certificateInfo.serialNumber}\n` +
27
+ ` Valid from: ${cert.certificateInfo.validFrom}\n` +
28
+ ` Valid to: ${cert.certificateInfo.validTo}\n` +
29
+ ` Created: ${cert.createdOn}\n` +
30
+ ` Updated: ${cert.updatedOn}`);
31
+ }
32
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/ca-certificate/describe/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EACL,yBAAyB,EACzB,mCAAmC,EACnC,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAMhC,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAuB;IACpD,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACzB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;IAE/B,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAC/B,gBAAgB,OAAO,8BAA8B,EACrD;QACE,SAAS,EAAE,mCAAmC;QAC9C,YAAY,EAAE,2CAA2C;KAC1D,CACF,CAAC;IAEF,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC;IACxD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,yBAAyB,CACvB,kCAAkC,MAAM,2BAA2B,OAAO,GAAG,CAC9E,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC3B,MAAM,mCAAmC,CAAC,IAAI,CAAC,CAAC;QAChD,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAClE,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAChE,oBAAoB,CAClB,SAAS,IAAI,CAAC,EAAE,IAAI;QAClB,WAAW,IAAI,CAAC,IAAI,IAAI;QACxB,cAAc,OAAO,IAAI;QACzB,aAAa,MAAM,IAAI;QACvB,aAAa,IAAI,CAAC,eAAe,CAAC,YAAY,IAAI;QAClD,iBAAiB,IAAI,CAAC,eAAe,CAAC,SAAS,IAAI;QACnD,eAAe,IAAI,CAAC,eAAe,CAAC,OAAO,IAAI;QAC/C,cAAc,IAAI,CAAC,SAAS,IAAI;QAChC,cAAc,IAAI,CAAC,SAAS,EAAE,CACjC,CAAC;AACJ,CAAC","sourcesContent":["import { createApiClient } from \"../../common/api/client.js\";\nimport {\n printDiagnosticsToConsole,\n printJsonToConsoleAndExitGracefully,\n printResultToConsole,\n} from \"../../common/output.js\";\nimport { CaCertificateListResponse, DescribeArguments } from \"../models.js\";\n\n// developer-api does not currently expose GET /client-mtls-ca-certificates/{id},\n// so we fetch the list and filter client-side. Switch to a direct GET when the\n// route is added.\nexport async function describe(argv: DescribeArguments) {\n const { account } = argv;\n const certId = argv[\"cert-id\"];\n\n const client = createApiClient({ authToken: argv.authToken });\n const response = await client.get<CaCertificateListResponse>(\n `/v1/accounts/${account}/client-mtls-ca-certificates`,\n {\n operation: \"Failed to describe CA certificate\",\n errorMessage: \"Error: Failed to describe CA certificate.\",\n }\n );\n\n const cert = response.data.find((c) => c.id === certId);\n if (!cert) {\n printDiagnosticsToConsole(\n `Error: CA certificate with ID '${certId}' not found in account '${account}'`\n );\n return;\n }\n\n if (argv.output === \"json\") {\n await printJsonToConsoleAndExitGracefully(cert);\n return;\n }\n\n const subject = cert.certificateInfo.subject.replace(/\\n/g, \", \");\n const issuer = cert.certificateInfo.issuer.replace(/\\n/g, \", \");\n printResultToConsole(\n ` ID: ${cert.id}\\n` +\n ` Name: ${cert.name}\\n` +\n ` Subject: ${subject}\\n` +\n ` Issuer: ${issuer}\\n` +\n ` Serial: ${cert.certificateInfo.serialNumber}\\n` +\n ` Valid from: ${cert.certificateInfo.validFrom}\\n` +\n ` Valid to: ${cert.certificateInfo.validTo}\\n` +\n ` Created: ${cert.createdOn}\\n` +\n ` Updated: ${cert.updatedOn}`\n );\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { ListArguments } from "../models.js";
2
+ export declare function list(argv: ListArguments): Promise<void>;
3
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/ca-certificate/list/handler.ts"],"names":[],"mappings":"AAKA,OAAO,EAA6B,aAAa,EAAE,MAAM,cAAc,CAAC;AAExE,wBAAsB,IAAI,CAAC,IAAI,EAAE,aAAa,iBAkC7C"}
@@ -0,0 +1,28 @@
1
+ import { createApiClient } from "../../common/api/client.js";
2
+ import { printJsonToConsoleAndExitGracefully, printResultToConsole, } from "../../common/output.js";
3
+ export async function list(argv) {
4
+ const { account } = argv;
5
+ const client = createApiClient({ authToken: argv.authToken });
6
+ const response = await client.get(`/v1/accounts/${account}/client-mtls-ca-certificates`, {
7
+ operation: "Failed to list CA certificates",
8
+ errorMessage: "Error: Failed to list CA certificates.",
9
+ });
10
+ if (argv.output === "json") {
11
+ await printJsonToConsoleAndExitGracefully(response);
12
+ return;
13
+ }
14
+ if (response.data.length === 0) {
15
+ printResultToConsole("No CA certificates found");
16
+ return;
17
+ }
18
+ printResultToConsole(`Found ${response.data.length} CA certificate(s):\n`);
19
+ for (const cert of response.data) {
20
+ const subject = cert.certificateInfo.subject.replace(/\n/g, ", ");
21
+ printResultToConsole(` ID: ${cert.id}\n` +
22
+ ` Name: ${cert.name}\n` +
23
+ ` Subject: ${subject}\n` +
24
+ ` Valid from: ${cert.certificateInfo.validFrom}\n` +
25
+ ` Valid to: ${cert.certificateInfo.validTo}\n`);
26
+ }
27
+ }
28
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/ca-certificate/list/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EACL,mCAAmC,EACnC,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAGhC,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAmB;IAC5C,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAEzB,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAC/B,gBAAgB,OAAO,8BAA8B,EACrD;QACE,SAAS,EAAE,gCAAgC;QAC3C,YAAY,EAAE,wCAAwC;KACvD,CACF,CAAC;IAEF,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC3B,MAAM,mCAAmC,CAAC,QAAQ,CAAC,CAAC;QACpD,OAAO;IACT,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,oBAAoB,CAAC,0BAA0B,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IAED,oBAAoB,CAAC,SAAS,QAAQ,CAAC,IAAI,CAAC,MAAM,uBAAuB,CAAC,CAAC;IAE3E,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAClE,oBAAoB,CAClB,SAAS,IAAI,CAAC,EAAE,IAAI;YAClB,WAAW,IAAI,CAAC,IAAI,IAAI;YACxB,cAAc,OAAO,IAAI;YACzB,iBAAiB,IAAI,CAAC,eAAe,CAAC,SAAS,IAAI;YACnD,eAAe,IAAI,CAAC,eAAe,CAAC,OAAO,IAAI,CAClD,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["import { createApiClient } from \"../../common/api/client.js\";\nimport {\n printJsonToConsoleAndExitGracefully,\n printResultToConsole,\n} from \"../../common/output.js\";\nimport { CaCertificateListResponse, ListArguments } from \"../models.js\";\n\nexport async function list(argv: ListArguments) {\n const { account } = argv;\n\n const client = createApiClient({ authToken: argv.authToken });\n const response = await client.get<CaCertificateListResponse>(\n `/v1/accounts/${account}/client-mtls-ca-certificates`,\n {\n operation: \"Failed to list CA certificates\",\n errorMessage: \"Error: Failed to list CA certificates.\",\n }\n );\n\n if (argv.output === \"json\") {\n await printJsonToConsoleAndExitGracefully(response);\n return;\n }\n\n if (response.data.length === 0) {\n printResultToConsole(\"No CA certificates found\");\n return;\n }\n\n printResultToConsole(`Found ${response.data.length} CA certificate(s):\\n`);\n\n for (const cert of response.data) {\n const subject = cert.certificateInfo.subject.replace(/\\n/g, \", \");\n printResultToConsole(\n ` ID: ${cert.id}\\n` +\n ` Name: ${cert.name}\\n` +\n ` Subject: ${subject}\\n` +\n ` Valid from: ${cert.certificateInfo.validFrom}\\n` +\n ` Valid to: ${cert.certificateInfo.validTo}\\n`\n );\n }\n}\n"]}
@@ -0,0 +1,51 @@
1
+ export interface CaCertificateInfo {
2
+ subject: string;
3
+ issuer: string;
4
+ validFrom: string;
5
+ validTo: string;
6
+ serialNumber: string;
7
+ }
8
+ export interface CaCertificate {
9
+ id: string;
10
+ name: string;
11
+ certificateInfo: CaCertificateInfo;
12
+ createdOn: string;
13
+ updatedOn: string;
14
+ }
15
+ export interface CaCertificateListResponse {
16
+ data: CaCertificate[];
17
+ offset: number;
18
+ limit: number;
19
+ }
20
+ export interface CreateArguments {
21
+ account: string;
22
+ authToken: string;
23
+ name: string;
24
+ cert: string;
25
+ output?: "default" | "json";
26
+ }
27
+ export interface ListArguments {
28
+ account: string;
29
+ authToken: string;
30
+ output?: "default" | "json";
31
+ }
32
+ export interface UpdateArguments {
33
+ account: string;
34
+ authToken: string;
35
+ "cert-id": string;
36
+ name: string;
37
+ output?: "default" | "json";
38
+ }
39
+ export interface DeleteArguments {
40
+ account: string;
41
+ authToken: string;
42
+ "cert-id": string;
43
+ output?: "default" | "json";
44
+ }
45
+ export interface DescribeArguments {
46
+ account: string;
47
+ authToken: string;
48
+ "cert-id": string;
49
+ output?: "default" | "json";
50
+ }
51
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/ca-certificate/models.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,iBAAiB,CAAC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,aAAa,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC7B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/ca-certificate/models.ts"],"names":[],"mappings":"","sourcesContent":["export interface CaCertificateInfo {\n subject: string;\n issuer: string;\n validFrom: string;\n validTo: string;\n serialNumber: string;\n}\n\nexport interface CaCertificate {\n id: string;\n name: string;\n certificateInfo: CaCertificateInfo;\n createdOn: string;\n updatedOn: string;\n}\n\nexport interface CaCertificateListResponse {\n data: CaCertificate[];\n offset: number;\n limit: number;\n}\n\nexport interface CreateArguments {\n account: string;\n authToken: string;\n name: string;\n cert: string;\n output?: \"default\" | \"json\";\n}\n\nexport interface ListArguments {\n account: string;\n authToken: string;\n output?: \"default\" | \"json\";\n}\n\nexport interface UpdateArguments {\n account: string;\n authToken: string;\n \"cert-id\": string;\n name: string;\n output?: \"default\" | \"json\";\n}\n\nexport interface DeleteArguments {\n account: string;\n authToken: string;\n \"cert-id\": string;\n output?: \"default\" | \"json\";\n}\n\nexport interface DescribeArguments {\n account: string;\n authToken: string;\n \"cert-id\": string;\n output?: \"default\" | \"json\";\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { UpdateArguments } from "../models.js";
2
+ export declare function update(argv: UpdateArguments): Promise<void>;
3
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/ca-certificate/update/handler.ts"],"names":[],"mappings":"AAMA,OAAO,EAAiB,eAAe,EAAE,MAAM,cAAc,CAAC;AAG9D,wBAAsB,MAAM,CAAC,IAAI,EAAE,eAAe,iBA8BjD"}
@@ -0,0 +1,26 @@
1
+ import { createApiClient } from "../../common/api/client.js";
2
+ import { printDiagnosticsToConsole, printJsonToConsoleAndExitGracefully, printResultToConsole, } from "../../common/output.js";
3
+ import { validateName } from "../validation.js";
4
+ export async function update(argv) {
5
+ const { account } = argv;
6
+ const certId = argv["cert-id"];
7
+ const nameError = validateName(argv.name);
8
+ if (nameError) {
9
+ printDiagnosticsToConsole(`Error: --name is invalid. ${nameError.message}`);
10
+ return;
11
+ }
12
+ const client = createApiClient({ authToken: argv.authToken });
13
+ const cert = await client.patch(`/v1/accounts/${account}/client-mtls-ca-certificates/${encodeURIComponent(certId)}`, {
14
+ operation: "Failed to update CA certificate",
15
+ errorMessage: "Error: Failed to update CA certificate.",
16
+ body: {
17
+ name: argv.name,
18
+ },
19
+ });
20
+ if (argv.output === "json") {
21
+ await printJsonToConsoleAndExitGracefully(cert);
22
+ return;
23
+ }
24
+ printResultToConsole(`CA certificate '${cert.name}' (${cert.id}) updated successfully`);
25
+ }
26
+ //# sourceMappingURL=handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/ca-certificate/update/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EACL,yBAAyB,EACzB,mCAAmC,EACnC,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAqB;IAChD,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACzB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;IAE/B,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,SAAS,EAAE,CAAC;QACd,yBAAyB,CAAC,6BAA6B,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5E,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,KAAK,CAC7B,gBAAgB,OAAO,gCAAgC,kBAAkB,CAAC,MAAM,CAAC,EAAE,EACnF;QACE,SAAS,EAAE,iCAAiC;QAC5C,YAAY,EAAE,yCAAyC;QACvD,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB;KACF,CACF,CAAC;IAEF,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC3B,MAAM,mCAAmC,CAAC,IAAI,CAAC,CAAC;QAChD,OAAO;IACT,CAAC;IAED,oBAAoB,CAClB,mBAAmB,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,wBAAwB,CAClE,CAAC;AACJ,CAAC","sourcesContent":["import { createApiClient } from \"../../common/api/client.js\";\nimport {\n printDiagnosticsToConsole,\n printJsonToConsoleAndExitGracefully,\n printResultToConsole,\n} from \"../../common/output.js\";\nimport { CaCertificate, UpdateArguments } from \"../models.js\";\nimport { validateName } from \"../validation.js\";\n\nexport async function update(argv: UpdateArguments) {\n const { account } = argv;\n const certId = argv[\"cert-id\"];\n\n const nameError = validateName(argv.name);\n if (nameError) {\n printDiagnosticsToConsole(`Error: --name is invalid. ${nameError.message}`);\n return;\n }\n\n const client = createApiClient({ authToken: argv.authToken });\n const cert = await client.patch<CaCertificate>(\n `/v1/accounts/${account}/client-mtls-ca-certificates/${encodeURIComponent(certId)}`,\n {\n operation: \"Failed to update CA certificate\",\n errorMessage: \"Error: Failed to update CA certificate.\",\n body: {\n name: argv.name,\n },\n }\n );\n\n if (argv.output === \"json\") {\n await printJsonToConsoleAndExitGracefully(cert);\n return;\n }\n\n printResultToConsole(\n `CA certificate '${cert.name}' (${cert.id}) updated successfully`\n );\n}\n"]}
@@ -0,0 +1,21 @@
1
+ export interface ValidationError {
2
+ message: string;
3
+ hint?: string;
4
+ }
5
+ export declare function validateName(name: string): ValidationError | null;
6
+ export interface PemCertificateDetails {
7
+ subject: string;
8
+ issuer: string;
9
+ validFrom: string;
10
+ validTo: string;
11
+ serialNumber: string;
12
+ isCa: boolean;
13
+ }
14
+ export declare function parseAndValidateCaCertificate(
15
+ pem: string,
16
+ now?: Date
17
+ ): PemCertificateDetails | ValidationError;
18
+ export declare function isValidationError(
19
+ result: PemCertificateDetails | ValidationError
20
+ ): result is ValidationError;
21
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/ca-certificate/validation.ts"],"names":[],"mappings":"AAwDA,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAmBjE;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,OAAO,CAAC;CACf;AAMD,wBAAgB,6BAA6B,CAC3C,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,IAAiB,GACrB,qBAAqB,GAAG,eAAe,CAsEzC;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,qBAAqB,GAAG,eAAe,GAC9C,MAAM,IAAI,eAAe,CAE3B"}
@@ -0,0 +1,135 @@
1
+ import crypto from "node:crypto";
2
+ const MAX_NAME_LENGTH = 120;
3
+ const PEM_BEGIN = "-----BEGIN CERTIFICATE-----";
4
+ const PEM_END = "-----END CERTIFICATE-----";
5
+ const JS_VARIABLE_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
6
+ const JS_RESERVED_KEYWORDS = new Set([
7
+ "break",
8
+ "case",
9
+ "catch",
10
+ "class",
11
+ "const",
12
+ "continue",
13
+ "debugger",
14
+ "default",
15
+ "delete",
16
+ "do",
17
+ "else",
18
+ "export",
19
+ "extends",
20
+ "finally",
21
+ "for",
22
+ "function",
23
+ "if",
24
+ "import",
25
+ "in",
26
+ "instanceof",
27
+ "let",
28
+ "new",
29
+ "return",
30
+ "super",
31
+ "switch",
32
+ "this",
33
+ "throw",
34
+ "try",
35
+ "typeof",
36
+ "var",
37
+ "void",
38
+ "while",
39
+ "with",
40
+ "yield",
41
+ "enum",
42
+ "implements",
43
+ "interface",
44
+ "package",
45
+ "private",
46
+ "protected",
47
+ "public",
48
+ "static",
49
+ "await",
50
+ ]);
51
+ export function validateName(name) {
52
+ if (name.length === 0) {
53
+ return { message: "Name cannot be empty" };
54
+ }
55
+ if (name.length > MAX_NAME_LENGTH) {
56
+ return {
57
+ message: `Name must be ${MAX_NAME_LENGTH} characters or fewer (got ${name.length})`,
58
+ };
59
+ }
60
+ if (!JS_VARIABLE_REGEX.test(name)) {
61
+ return {
62
+ message: "Name must be a valid JavaScript variable name (start with a letter, _, or $, and contain only letters, digits, _, or $)",
63
+ };
64
+ }
65
+ if (JS_RESERVED_KEYWORDS.has(name.toLowerCase())) {
66
+ return { message: "Name cannot be a JavaScript reserved keyword" };
67
+ }
68
+ return null;
69
+ }
70
+ export function parseAndValidateCaCertificate(pem, now = new Date()) {
71
+ if (!pem.includes(PEM_BEGIN) || !pem.includes(PEM_END)) {
72
+ if (/-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/.test(pem)) {
73
+ return {
74
+ message: "File is a private key, not a certificate",
75
+ hint: "The `--cert` flag expects the public CA certificate, not a private key. " +
76
+ "CA certs only contain the public half; the private key stays with your PKI. " +
77
+ "If your CA is bundled in a single PEM file, pass it as-is — the certificate block will be picked up.",
78
+ };
79
+ }
80
+ if (/-----BEGIN CERTIFICATE REQUEST-----/.test(pem)) {
81
+ return {
82
+ message: "File is a certificate signing request (CSR), not a certificate",
83
+ hint: "A CSR is the request you send to a CA to get a certificate issued. Pass the issued CA certificate instead.",
84
+ };
85
+ }
86
+ if (/-----BEGIN [A-Z0-9 ]+-----/.test(pem)) {
87
+ return {
88
+ message: "File is a PEM block but not a certificate",
89
+ hint: `Expected a PEM block starting with "${PEM_BEGIN}".`,
90
+ };
91
+ }
92
+ return {
93
+ message: "File does not appear to be a PEM-encoded certificate",
94
+ hint: `Expected to find "${PEM_BEGIN}" and "${PEM_END}" in the file.\n` +
95
+ "If you have a DER-encoded certificate, convert it with:\n" +
96
+ " openssl x509 -in <file> -inform der -out cert.pem",
97
+ };
98
+ }
99
+ let cert;
100
+ try {
101
+ cert = new crypto.X509Certificate(pem);
102
+ }
103
+ catch (err) {
104
+ return {
105
+ message: "Failed to parse certificate",
106
+ hint: err instanceof Error ? err.message : String(err),
107
+ };
108
+ }
109
+ if (!cert.ca) {
110
+ return {
111
+ message: "The certificate is not a CA certificate",
112
+ hint: "Expected a certificate with the CA basic constraint set to TRUE " +
113
+ "(typically the root or intermediate CA that signs your client certs), " +
114
+ "not a leaf/client certificate.",
115
+ };
116
+ }
117
+ const validTo = new Date(cert.validTo);
118
+ if (!Number.isNaN(validTo.getTime()) && validTo < now) {
119
+ return {
120
+ message: `Certificate has already expired (validTo=${cert.validTo})`,
121
+ };
122
+ }
123
+ return {
124
+ subject: cert.subject,
125
+ issuer: cert.issuer,
126
+ validFrom: cert.validFrom,
127
+ validTo: cert.validTo,
128
+ serialNumber: cert.serialNumber,
129
+ isCa: cert.ca,
130
+ };
131
+ }
132
+ export function isValidationError(result) {
133
+ return "message" in result;
134
+ }
135
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/ca-certificate/validation.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"node:crypto\";\n\nconst MAX_NAME_LENGTH = 120;\nconst PEM_BEGIN = \"-----BEGIN CERTIFICATE-----\";\nconst PEM_END = \"-----END CERTIFICATE-----\";\nconst JS_VARIABLE_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;\n\n// Kept in sync with tenant-api's reservedKeywords list in\n// apps/tenant-api/src/utils/certificate-validation.ts. Updating one without\n// the other lets bad names slip past the CLI and fail on the server.\nconst JS_RESERVED_KEYWORDS = new Set([\n \"break\",\n \"case\",\n \"catch\",\n \"class\",\n \"const\",\n \"continue\",\n \"debugger\",\n \"default\",\n \"delete\",\n \"do\",\n \"else\",\n \"export\",\n \"extends\",\n \"finally\",\n \"for\",\n \"function\",\n \"if\",\n \"import\",\n \"in\",\n \"instanceof\",\n \"let\",\n \"new\",\n \"return\",\n \"super\",\n \"switch\",\n \"this\",\n \"throw\",\n \"try\",\n \"typeof\",\n \"var\",\n \"void\",\n \"while\",\n \"with\",\n \"yield\",\n \"enum\",\n \"implements\",\n \"interface\",\n \"package\",\n \"private\",\n \"protected\",\n \"public\",\n \"static\",\n \"await\",\n]);\n\nexport interface ValidationError {\n message: string;\n hint?: string;\n}\n\n// Mirrors tenant-api's validateCertificateName so the CLI rejects bad names\n// before a network round trip.\nexport function validateName(name: string): ValidationError | null {\n if (name.length === 0) {\n return { message: \"Name cannot be empty\" };\n }\n if (name.length > MAX_NAME_LENGTH) {\n return {\n message: `Name must be ${MAX_NAME_LENGTH} characters or fewer (got ${name.length})`,\n };\n }\n if (!JS_VARIABLE_REGEX.test(name)) {\n return {\n message:\n \"Name must be a valid JavaScript variable name (start with a letter, _, or $, and contain only letters, digits, _, or $)\",\n };\n }\n if (JS_RESERVED_KEYWORDS.has(name.toLowerCase())) {\n return { message: \"Name cannot be a JavaScript reserved keyword\" };\n }\n return null;\n}\n\nexport interface PemCertificateDetails {\n subject: string;\n issuer: string;\n validFrom: string;\n validTo: string;\n serialNumber: string;\n isCa: boolean;\n}\n\n// Mirrors tenant-api's parseCertificateWithDetails. Returns the parsed\n// certificate details or a ValidationError that the CLI can surface directly,\n// avoiding a round trip when the input is obviously wrong.\n// `now` is injectable for testing the expiry branch portably.\nexport function parseAndValidateCaCertificate(\n pem: string,\n now: Date = new Date()\n): PemCertificateDetails | ValidationError {\n if (!pem.includes(PEM_BEGIN) || !pem.includes(PEM_END)) {\n // Detect common PEM header variants so the hint actually matches the\n // mistake the user made.\n if (/-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/.test(pem)) {\n return {\n message: \"File is a private key, not a certificate\",\n hint:\n \"The `--cert` flag expects the public CA certificate, not a private key. \" +\n \"CA certs only contain the public half; the private key stays with your PKI. \" +\n \"If your CA is bundled in a single PEM file, pass it as-is — the certificate block will be picked up.\",\n };\n }\n if (/-----BEGIN CERTIFICATE REQUEST-----/.test(pem)) {\n return {\n message:\n \"File is a certificate signing request (CSR), not a certificate\",\n hint: \"A CSR is the request you send to a CA to get a certificate issued. Pass the issued CA certificate instead.\",\n };\n }\n if (/-----BEGIN [A-Z0-9 ]+-----/.test(pem)) {\n return {\n message: \"File is a PEM block but not a certificate\",\n hint: `Expected a PEM block starting with \"${PEM_BEGIN}\".`,\n };\n }\n return {\n message: \"File does not appear to be a PEM-encoded certificate\",\n hint:\n `Expected to find \"${PEM_BEGIN}\" and \"${PEM_END}\" in the file.\\n` +\n \"If you have a DER-encoded certificate, convert it with:\\n\" +\n \" openssl x509 -in <file> -inform der -out cert.pem\",\n };\n }\n\n let cert: crypto.X509Certificate;\n try {\n cert = new crypto.X509Certificate(pem);\n } catch (err) {\n return {\n message: \"Failed to parse certificate\",\n hint: err instanceof Error ? err.message : String(err),\n };\n }\n\n if (!cert.ca) {\n return {\n message: \"The certificate is not a CA certificate\",\n hint:\n \"Expected a certificate with the CA basic constraint set to TRUE \" +\n \"(typically the root or intermediate CA that signs your client certs), \" +\n \"not a leaf/client certificate.\",\n };\n }\n\n const validTo = new Date(cert.validTo);\n if (!Number.isNaN(validTo.getTime()) && validTo < now) {\n return {\n message: `Certificate has already expired (validTo=${cert.validTo})`,\n };\n }\n\n return {\n subject: cert.subject,\n issuer: cert.issuer,\n validFrom: cert.validFrom,\n validTo: cert.validTo,\n serialNumber: cert.serialNumber,\n isCa: cert.ca,\n };\n}\n\nexport function isValidationError(\n result: PemCertificateDetails | ValidationError\n): result is ValidationError {\n return \"message\" in result;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=validation.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.test.d.ts","sourceRoot":"","sources":["../../src/ca-certificate/validation.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,131 @@
1
+ import assert from "node:assert";
2
+ import { describe, it } from "node:test";
3
+ import { isValidationError, parseAndValidateCaCertificate, validateName, } from "./validation.js";
4
+ const CA_PEM = `-----BEGIN CERTIFICATE-----
5
+ MIIC5jCCAc6gAwIBAgIUB4s5BPjuGshWHSZKkNIJJ7W7alkwDQYJKoZIhvcNAQEL
6
+ BQAwEjEQMA4GA1UEAwwHVGVzdCBjYTAgFw0yNjA1MTMwMDA1NDFaGA8yMTI2MDQx
7
+ OTAwMDU0MVowEjEQMA4GA1UEAwwHVGVzdCBjYTCCASIwDQYJKoZIhvcNAQEBBQAD
8
+ ggEPADCCAQoCggEBAK+8kcIOYXC5SKCnnEmddLKiVSon8NoLn8RABel0op+5i3J2
9
+ pnDBBWOy2nT5qWRI2N0tTK4tQn/jaGeiBP0BUu4z+Y/pcglveexyFWhtFstHyyUr
10
+ yiwhBhX3NEWHZGr/VShriKxojnTwWONpgQwq7On7k+We3JK7IEASvKLxhC1+hcch
11
+ CwP67zGDF6qJrfjBfdPSRoW8OomioTRyb7MyrWvRpKm/0rj9NYc7MxMYbgVffE6y
12
+ IVQ4UCsVw74DdebfdzBSJOwNa+2Fe8AwQ3QMVbzfE3qs6+nviQ1EJA/h0kWgIrCI
13
+ 3JvGpJinI0kDXEYx/4BTHVNfg1UdCOqPxxdrS18CAwEAAaMyMDAwDwYDVR0TAQH/
14
+ BAUwAwEB/zAdBgNVHQ4EFgQUuku+yW29ASY8vCZ7fBVA6L3r28YwDQYJKoZIhvcN
15
+ AQELBQADggEBAFaYAde91xdpST+LlokhbWanr8xiUr7jdHemjxGvBi/Zxs2VQIj2
16
+ +1Bh0dpxGk670nSc/Bq8jcivoiGoaRxT5rFVhtQOpYLgo+wKqNoYfEoEPrIrT4PO
17
+ seBrdMa9cduhs/Nx11Vgf5N56KomRO1a4AaIcvh6uGxrf1jfaCjaAKWTNNd9luzo
18
+ /IsRikl4QN0pZ1lIxdOdVMFhCp8V/+oEO6aw2FhFZlZKA+XLELHQzPBpuubQocuT
19
+ 9dLovPbpFD2UwgvpjXQYjpr5btZx+iupHfiXq7WI6EI3eG5UgTuOpK8g9rLDiX9f
20
+ ArcSyj6/ZV+MDtaEHyEJBdsp//aT6Kfpoek=
21
+ -----END CERTIFICATE-----
22
+ `;
23
+ const LEAF_PEM = `-----BEGIN CERTIFICATE-----
24
+ MIIC5zCCAc+gAwIBAgIUFG0P6P6J4YoBLyRH2pjt7RdV9sAwDQYJKoZIhvcNAQEL
25
+ BQAwFDESMBAGA1UEAwwJVGVzdCBsZWFmMCAXDTI2MDUxMzAwMDU0MVoYDzIxMjYw
26
+ NDE5MDAwNTQxWjAUMRIwEAYDVQQDDAlUZXN0IGxlYWYwggEiMA0GCSqGSIb3DQEB
27
+ AQUAA4IBDwAwggEKAoIBAQDc1H+Z9qbmSsTR1tDVEvMN94ayec1UZ/17eIDY55ho
28
+ N5UA3Blho2xLeXvWWpKpo6wTXONzpNak8qhccIGsuIogpparkYYPBG+86cofnGDC
29
+ m/T9wa8eLTvyrIyPfUjkYVU7Gfmsq08pF/GZHIHcJg/xdTOLKE8WgJi15zwi1ZOE
30
+ z/OtpGKlX2pnM7aq6mzUqamWo2WBPpFdtdLfCBtnUkoNtxWmn98Xj/AaoiBR0UAI
31
+ C8UQAEAv3yaZ8pBZoLLn68kFgkOdNAPnX2zi6B6uk7LWA90JUneL+fPb/89muxl+
32
+ uQ4NGgWINtG23OtELLtUIuNiZxEFEO0mxf+0pIYa/1VTAgMBAAGjLzAtMAwGA1Ud
33
+ EwEB/wQCMAAwHQYDVR0OBBYEFP5YdepOBrpmYPdem5awTb3ByLZ7MA0GCSqGSIb3
34
+ DQEBCwUAA4IBAQBZ9Bl8IcQ9VYxTQgO1U9wB+LcHJ2WXqVSQTlz+qwd+tyfnv0PM
35
+ O5/ouSYiCj3IBQ42N3z+QhLgZgvfGcC6qFvG67A1WV7n7ZV5D7Yb9CqE+NPUbx3V
36
+ 3GFBkIAv7U+4TKYPSK2YPXCb/D3rtel2j31tcMtODoT0LrHbwaOCGd8G+15rxBjP
37
+ dfHuC/nYYeKsplDhcdfemel73WbNzuqGNliQhEqhtlpGOhciHpd1Zlm7OgUINmCr
38
+ rfRfSGvBGDkuNRQIEhnFZXYhD0iCM/6D56/VykaqaQz+bPr04d0e0KvusFGsmapN
39
+ zC0Ztm1aNp0wB0vPNoEJrpQEmkB80cR1DXVR
40
+ -----END CERTIFICATE-----
41
+ `;
42
+ describe("validateName", () => {
43
+ it("accepts valid names", () => {
44
+ assert.strictEqual(validateName("my_ca"), null);
45
+ assert.strictEqual(validateName("CA1"), null);
46
+ assert.strictEqual(validateName("$abc"), null);
47
+ assert.strictEqual(validateName("_underscore"), null);
48
+ });
49
+ it("rejects empty names", () => {
50
+ const result = validateName("");
51
+ assert.ok(result);
52
+ assert.match(result.message, /empty/i);
53
+ });
54
+ it("rejects names over 120 characters", () => {
55
+ const result = validateName("a".repeat(121));
56
+ assert.ok(result);
57
+ assert.match(result.message, /120 characters/);
58
+ });
59
+ it("rejects names starting with a digit", () => {
60
+ const result = validateName("1ca");
61
+ assert.ok(result);
62
+ assert.match(result.message, /JavaScript variable name/);
63
+ });
64
+ it("rejects names with hyphens or spaces", () => {
65
+ assert.ok(validateName("my-ca"));
66
+ assert.ok(validateName("my ca"));
67
+ assert.ok(validateName("ca.example"));
68
+ });
69
+ it("rejects JavaScript reserved keywords", () => {
70
+ for (const keyword of ["class", "delete", "import", "return", "await"]) {
71
+ const result = validateName(keyword);
72
+ assert.ok(result, `expected ${keyword} to be rejected`);
73
+ assert.match(result.message, /reserved keyword/);
74
+ }
75
+ });
76
+ it("rejects reserved keywords case-insensitively", () => {
77
+ assert.ok(validateName("CLASS"));
78
+ assert.ok(validateName("Delete"));
79
+ });
80
+ });
81
+ describe("parseAndValidateCaCertificate", () => {
82
+ it("rejects garbage input", () => {
83
+ const result = parseAndValidateCaCertificate("not a certificate");
84
+ assert.ok(isValidationError(result));
85
+ assert.match(result.message, /PEM-encoded/);
86
+ assert.match(result.hint ?? "", /openssl x509.*-inform der/);
87
+ });
88
+ it("rejects a PKCS#8 private key with a key-specific hint", () => {
89
+ const pem = `-----BEGIN PRIVATE KEY-----\nfoo\n-----END PRIVATE KEY-----`;
90
+ const result = parseAndValidateCaCertificate(pem);
91
+ assert.ok(isValidationError(result));
92
+ assert.match(result.message, /private key/i);
93
+ assert.match(result.hint ?? "", /public CA certificate/);
94
+ });
95
+ it("rejects an RSA private key with a key-specific hint", () => {
96
+ const pem = `-----BEGIN RSA PRIVATE KEY-----\nfoo\n-----END RSA PRIVATE KEY-----`;
97
+ const result = parseAndValidateCaCertificate(pem);
98
+ assert.ok(isValidationError(result));
99
+ assert.match(result.message, /private key/i);
100
+ });
101
+ it("rejects a CSR with a CSR-specific hint", () => {
102
+ const pem = `-----BEGIN CERTIFICATE REQUEST-----\nfoo\n-----END CERTIFICATE REQUEST-----`;
103
+ const result = parseAndValidateCaCertificate(pem);
104
+ assert.ok(isValidationError(result));
105
+ assert.match(result.message, /CSR|signing request/i);
106
+ });
107
+ it("rejects a PEM-shaped but corrupt certificate", () => {
108
+ const pem = `-----BEGIN CERTIFICATE-----\nnot-real-base64\n-----END CERTIFICATE-----`;
109
+ const result = parseAndValidateCaCertificate(pem);
110
+ assert.ok(isValidationError(result));
111
+ assert.match(result.message, /Failed to parse/);
112
+ });
113
+ it("accepts a valid CA certificate", () => {
114
+ const result = parseAndValidateCaCertificate(CA_PEM);
115
+ assert.ok(!isValidationError(result), JSON.stringify(result));
116
+ assert.strictEqual(result.isCa, true);
117
+ assert.match(result.subject, /Test ca/i);
118
+ });
119
+ it("rejects a leaf (non-CA) certificate", () => {
120
+ const result = parseAndValidateCaCertificate(LEAF_PEM);
121
+ assert.ok(isValidationError(result));
122
+ assert.match(result.message, /not a CA certificate/);
123
+ });
124
+ it("rejects a CA certificate that is expired relative to `now`", () => {
125
+ const farFuture = new Date("2200-01-01T00:00:00Z");
126
+ const result = parseAndValidateCaCertificate(CA_PEM, farFuture);
127
+ assert.ok(isValidationError(result));
128
+ assert.match(result.message, /expired/);
129
+ });
130
+ });
131
+ //# sourceMappingURL=validation.test.js.map