import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' /** * Auswertung der Umgebungsvariablen. * * Der Anlass für diese Datei war ein Fehler im Betrieb: docker compose * reicht `ENC_KEY_V2` immer durch — mit leerem Wert, wenn in der .env * keiner steht. Die Schlüsselsammlung erkannte Schlüssel aber am * Variablennamen statt am Inhalt, fand also ein leeres `ENC_KEY_V2` und * brach ab. Die Meldung lautete „ENC_KEY_V2 fehlt", obwohl niemand einen * zweiten Schlüssel wollte. * * Jede Prüfung hier lädt `@/lib/env` frisch, weil die Werte beim ersten * Zugriff gemerkt werden. */ const ECHT = Buffer.alloc(32, 7).toString('base64') const ECHT_ZWEI = Buffer.alloc(32, 9).toString('base64') let vorher: NodeJS.ProcessEnv async function frischesEnv() { // Leert die Modulregistrierung, damit der naechste Import das Modul neu // auswertet - die Schluessel werden sonst nur beim ersten Mal gelesen. vi.resetModules() const { env } = await import('@/lib/env') return env } beforeEach(() => { vorher = { ...process.env } for (const name of Object.keys(process.env)) { if (/^ENC_KEY_V\d+$/.test(name)) delete process.env[name] } delete process.env.ENC_KEY_AKTIV }) afterEach(() => { process.env = vorher }) describe('Verschlüsselungsschlüssel aus der Umgebung', () => { it('nimmt einen einzelnen Schlüssel an', async () => { process.env.ENC_KEY_V1 = ECHT const env = await frischesEnv() expect([...env.verschluesselungsschluessel.keys()]).toEqual([1]) expect(env.aktiveSchluesselversion).toBe(1) }) it('überspringt eine leere Schlüsselvariable', async () => { // Genau das setzt docker compose, wenn in der .env kein zweiter // Schlüssel steht: ENC_KEY_V2: ${ENC_KEY_V2:-} process.env.ENC_KEY_V1 = ECHT process.env.ENC_KEY_V2 = '' const env = await frischesEnv() expect([...env.verschluesselungsschluessel.keys()]).toEqual([1]) expect(env.aktiveSchluesselversion).toBe(1) }) it('überspringt eine Variable, in der nur Leerzeichen stehen', async () => { process.env.ENC_KEY_V1 = ECHT process.env.ENC_KEY_V2 = ' ' const env = await frischesEnv() expect([...env.verschluesselungsschluessel.keys()]).toEqual([1]) }) it('nimmt beide Schlüssel an, wenn wirklich rotiert wird', async () => { process.env.ENC_KEY_V1 = ECHT process.env.ENC_KEY_V2 = ECHT_ZWEI process.env.ENC_KEY_AKTIV = '2' const env = await frischesEnv() expect([...env.verschluesselungsschluessel.keys()].sort()).toEqual([1, 2]) expect(env.aktiveSchluesselversion).toBe(2) }) it('sagt beim Rotieren deutlich, wenn der neue Schlüssel fehlt', async () => { process.env.ENC_KEY_V1 = ECHT process.env.ENC_KEY_V2 = '' process.env.ENC_KEY_AKTIV = '2' const env = await frischesEnv() expect(() => env.aktiveSchluesselversion).toThrow(/ENC_KEY_AKTIV=2/) // Die Meldung nennt, was da ist, und die richtige Reihenfolge. expect(() => env.aktiveSchluesselversion).toThrow(/Vorhanden sind die Versionen: 1/) expect(() => env.aktiveSchluesselversion).toThrow(/zuerst den neuen Schluessel/) }) it('beschwert sich, wenn gar kein Schlüssel gesetzt ist', async () => { process.env.ENC_KEY_V2 = '' const env = await frischesEnv() expect(() => env.verschluesselungsschluessel).toThrow(/mindestens ENC_KEY_V1/) }) it('weist einen Schlüssel falscher Länge ab', async () => { process.env.ENC_KEY_V1 = Buffer.alloc(16, 1).toString('base64') const env = await frischesEnv() expect(() => env.verschluesselungsschluessel).toThrow(/32 Bytes/) }) })