import { describe, test, expect } from 'vitest' import { loadDataPlaneConfig } from '../data-plane/config.js' const base = { BASE_DOMAIN: 'term.example.com', TLS_CERT_PATH: '/etc/relay/cert.pem', TLS_KEY_PATH: '/etc/relay/key.pem', AGENT_CA_CERT_PATH: '/etc/relay/ca.pem', RELAY_NODE_ID: 'node-1', } satisfies NodeJS.ProcessEnv describe('loadDataPlaneConfig (T1, INV9 fail-fast)', () => { test('happy path returns a frozen typed config with defaults applied', () => { const cfg = loadDataPlaneConfig(base) expect(cfg.baseDomain).toBe('term.example.com') expect(cfg.bindHost).toBe('0.0.0.0') expect(cfg.maxFrameBytes).toBe(1024 * 1024) expect(cfg.initialWindowBytes).toBe(256 * 1024) expect(cfg.heartbeatIntervalMs).toBe(15_000) expect(cfg.routeTtlMs).toBe(45_000) // agentCaChainPath falls back to agentCaCertPath when unset. expect(cfg.agentCaChainPath).toBe('/etc/relay/ca.pem') expect(Object.isFrozen(cfg)).toBe(true) }) test('throws when BASE_DOMAIN is missing', () => { expect(() => loadDataPlaneConfig({ ...base, BASE_DOMAIN: undefined })).toThrow(/baseDomain/) }) test('throws when TLS_CERT_PATH / TLS_KEY_PATH missing (fail-fast)', () => { expect(() => loadDataPlaneConfig({ ...base, TLS_CERT_PATH: undefined })).toThrow(/tlsCertPath/) expect(() => loadDataPlaneConfig({ ...base, TLS_KEY_PATH: undefined })).toThrow(/tlsKeyPath/) }) test('throws when AGENT_CA_CERT_PATH (mTLS trust-anchor) missing — Finding-4 footgun', () => { expect(() => loadDataPlaneConfig({ ...base, AGENT_CA_CERT_PATH: undefined })).toThrow( /agentCaCertPath/, ) }) test('throws on non-numeric MAX_FRAME_BYTES', () => { expect(() => loadDataPlaneConfig({ ...base, MAX_FRAME_BYTES: 'not-a-number' })).toThrow( /maxFrameBytes/, ) }) test('error message never echoes secret values (INV9)', () => { try { loadDataPlaneConfig({ ...base, TLS_KEY_PATH: undefined, MAX_FRAME_BYTES: 'xyz' }) throw new Error('should have thrown') } catch (e) { const msg = (e as Error).message expect(msg).not.toContain('/etc/relay/key.pem') expect(msg).not.toContain('xyz') } }) })