import { describe, test, expect } from 'vitest' import { loadEnv, DEFAULT_PAIRING_TTL_SEC, DEFAULT_PAIRING_MAX_REDEEM_ATTEMPTS } from '../src/env.js' import { bytesToBase64 } from '../src/util/bytes.js' const validPubkey = bytesToBase64(new Uint8Array(32).fill(7)) const base = (): NodeJS.ProcessEnv => ({ PG_URL: 'postgres://u:p@localhost:5432/cp', REDIS_URL: 'redis://localhost:6379', CAPABILITY_SIGN_PUBKEY_B64: validPubkey, CA_INTERMEDIATE_KMS_KEY_REF: 'kms://key/intermediate', CA_INTERMEDIATE_CERT_PATH: '/etc/cp/intermediate.pem', NODE_MTLS_TRUST_BUNDLE_PATH: '/etc/cp/node-ca.pem', BASE_DOMAIN: 'term.example.com', }) describe('T1 loadEnv (INV9 fail-fast)', () => { test('empty env throws listing every missing required key', () => { let msg = '' try { loadEnv({}) } catch (e) { msg = e instanceof Error ? e.message : '' } expect(msg).toContain('PG_URL') expect(msg).toContain('REDIS_URL') expect(msg).toContain('CAPABILITY_SIGN_PUBKEY_B64') expect(msg).toContain('CA_INTERMEDIATE_KMS_KEY_REF') expect(msg).toContain('BASE_DOMAIN') }) test('bad pgUrl throws', () => { expect(() => loadEnv({ ...base(), PG_URL: 'not a url' })).toThrow(/PG_URL/) }) test('valid map parses', () => { const env = loadEnv(base()) expect(env.baseDomain).toBe('term.example.com') expect(env.capabilitySignPubkey.length).toBe(32) }) test('pairing ttl / max-attempts default when unset', () => { const env = loadEnv(base()) expect(env.pairingTtlSec).toBe(DEFAULT_PAIRING_TTL_SEC) expect(env.pairingMaxRedeemAttempts).toBe(DEFAULT_PAIRING_MAX_REDEEM_ATTEMPTS) }) test('explicit pairing overrides parse', () => { const env = loadEnv({ ...base(), PAIRING_TTL_SEC: '900', PAIRING_MAX_REDEEM_ATTEMPTS: '3' }) expect(env.pairingTtlSec).toBe(900) expect(env.pairingMaxRedeemAttempts).toBe(3) }) test('never echoes secret VALUES on failure (INV9)', () => { const secret = bytesToBase64(new Uint8Array(32).fill(9)) try { loadEnv({ ...base(), CAPABILITY_SIGN_PUBKEY_B64: secret, PG_URL: 'bad' }) } catch (e) { const msg = e instanceof Error ? e.message : '' expect(msg).not.toContain(secret) } }) test('capability pubkey wrong length rejected', () => { const short = bytesToBase64(new Uint8Array(16)) expect(() => loadEnv({ ...base(), CAPABILITY_SIGN_PUBKEY_B64: short })).toThrow(/32 bytes/) }) })