From a06694f9152ed8fca1415d1a52a2340a55977ee7 Mon Sep 17 00:00:00 2001 From: Schalli Date: Wed, 1 Jul 2026 23:18:08 +0200 Subject: [PATCH] test(09-01): add failing spec for cert-manager seed + helpers (RED) - Test: seedCertManagerModule calls seedModule with slug='cert-manager', category='security-tools', isSystem=true - Test: detectFormat returns pem/der/pfx/p7b based on extension + content sniff - Test: getFingerprint returns uppercase colon-separated hex (sha1 + sha256) - Test: parsePemChain returns array of length 2 for two concatenated PEMs --- .../cert-manager/cert-manager.service.spec.ts | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 apps/api/src/cert-manager/cert-manager.service.spec.ts diff --git a/apps/api/src/cert-manager/cert-manager.service.spec.ts b/apps/api/src/cert-manager/cert-manager.service.spec.ts new file mode 100644 index 0000000..eef1a67 --- /dev/null +++ b/apps/api/src/cert-manager/cert-manager.service.spec.ts @@ -0,0 +1,130 @@ +import * as forge from 'node-forge'; +import { beforeAll, describe, expect, it, vi } from 'vitest'; +import { seedCertManagerModule } from './cert-manager.seed'; +import { CertManagerService } from './cert-manager.service'; + +// --------------------------------------------------------------------------- +// Test helpers +// --------------------------------------------------------------------------- + +/** Generate a self-signed X.509 cert via node-forge (RSA 1024 — fast for tests) */ +function generateSelfSignedCert(): forge.pki.Certificate { + const keys = forge.pki.rsa.generateKeyPair(1024); + const cert = forge.pki.createCertificate(); + cert.publicKey = keys.publicKey; + cert.serialNumber = '01'; + cert.validity.notBefore = new Date(); + cert.validity.notAfter = new Date(); + cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1); + + const attrs = [{ name: 'commonName', value: 'test.example.com' }]; + cert.setSubject(attrs); + cert.setIssuer(attrs); + cert.sign(keys.privateKey, forge.md.sha256.create()); + return cert; +} + +// --------------------------------------------------------------------------- +// Tests +// --------------------------------------------------------------------------- + +describe('seedCertManagerModule', () => { + it('calls moduleRegistryService.seedModule once with cert-manager slug', async () => { + const mockSeedModule = vi.fn().mockResolvedValue(undefined); + const mockModuleRegistryService = { seedModule: mockSeedModule } as any; + + await seedCertManagerModule(mockModuleRegistryService); + + expect(mockSeedModule).toHaveBeenCalledTimes(1); + const arg = mockSeedModule.mock.calls[0][0]; + expect(arg.slug).toBe('cert-manager'); + expect(arg.category).toBe('security-tools'); + expect(arg.isSystem).toBe(true); + }); +}); + +describe('CertManagerService helpers', () => { + let service: CertManagerService; + let testCert: forge.pki.Certificate; + + beforeAll(() => { + service = new CertManagerService(); + testCert = generateSelfSignedCert(); + }); + + // ------------------------------------------------------------------------- + // detectFormat + // ------------------------------------------------------------------------- + + describe('detectFormat', () => { + it('returns "pfx" for .pfx extension', () => { + const buf = Buffer.from([0x30, 0x82]); // arbitrary binary + expect(service.detectFormat('cert.pfx', buf)).toBe('pfx'); + }); + + it('returns "p7b" for .p7b extension', () => { + const buf = Buffer.from([0x30, 0x82]); + expect(service.detectFormat('cert.p7b', buf)).toBe('p7b'); + }); + + it('returns "der" for .der extension', () => { + const buf = Buffer.from([0x30, 0x82]); + expect(service.detectFormat('cert.der', buf)).toBe('der'); + }); + + it('returns "pem" for .pem extension', () => { + const buf = Buffer.from('-----BEGIN CERTIFICATE-----\nfake\n-----END CERTIFICATE-----'); + expect(service.detectFormat('cert.pem', buf)).toBe('pem'); + }); + + it('returns "pem" for .cer extension with PEM content', () => { + const buf = Buffer.from('-----BEGIN CERTIFICATE-----\nfake\n-----END CERTIFICATE-----'); + expect(service.detectFormat('cert.cer', buf)).toBe('pem'); + }); + + it('returns "der" for .cer extension with binary (non-PEM) content', () => { + const buf = Buffer.from([0x30, 0x82, 0x01, 0x00]); + expect(service.detectFormat('cert.cer', buf)).toBe('der'); + }); + }); + + // ------------------------------------------------------------------------- + // getFingerprint + // ------------------------------------------------------------------------- + + describe('getFingerprint', () => { + it('returns uppercase colon-separated hex for sha256', () => { + const fp = service.getFingerprint(testCert, 'sha256'); + // e.g. "AA:BB:CC:..." + expect(fp).toMatch(/^[0-9A-F]{2}(:[0-9A-F]{2})+$/); + }); + + it('returns uppercase colon-separated hex for sha1', () => { + const fp = service.getFingerprint(testCert, 'sha1'); + expect(fp).toMatch(/^[0-9A-F]{2}(:[0-9A-F]{2})+$/); + }); + }); + + // ------------------------------------------------------------------------- + // parsePemChain + // ------------------------------------------------------------------------- + + describe('parsePemChain', () => { + it('returns array of length 2 for two concatenated cert PEMs', () => { + const cert1 = generateSelfSignedCert(); + const cert2 = generateSelfSignedCert(); + const pem1 = forge.pki.certificateToPem(cert1); + const pem2 = forge.pki.certificateToPem(cert2); + const chain = pem1 + '\n' + pem2; + + const parsed = service.parsePemChain(chain); + expect(parsed).toHaveLength(2); + }); + + it('returns array of length 1 for a single PEM', () => { + const pem = forge.pki.certificateToPem(testCert); + const parsed = service.parsePemChain(pem); + expect(parsed).toHaveLength(1); + }); + }); +});