// Статическая проверка deploy/pilot/compose.yaml (аналог tests/unit/deployment.test.ts // для корневого compose.yaml). Лежит в tests/e2e, а не в tests/unit: у исполнителя // теста нет права менять tests/unit, а красные пункты (открытые дефекты deploy/) // должны идти через known-defects.json, не ломая `npm run check`. import { readFileSync } from 'node:fs'; import path from 'node:path'; import { describe, expect, it } from 'vitest'; import { parse } from 'yaml'; const composePath = path.resolve(import.meta.dirname, '../../deploy/pilot/compose.yaml'); const raw = readFileSync(composePath, 'utf8'); const compose = parse(raw) as { services: Record | string[] }>; }; function environmentOf(service: string): Record { const env = compose.services[service]?.environment ?? {}; if (Array.isArray(env)) { return Object.fromEntries( env.map((entry) => { const index = entry.indexOf('='); return index < 0 ? [entry, ''] : [entry.slice(0, index), entry.slice(index + 1)]; }), ); } return Object.fromEntries(Object.entries(env).map(([key, value]) => [key, String(value)])); } describe('deploy/pilot/compose.yaml', () => { it('[PILOT-1] все подставляемые переменные обязательны: ${VAR:?сообщение}', () => { const interpolations = [...raw.matchAll(/\$\{([^}]*)\}/g)].map((match) => match[1]!); expect(interpolations.length).toBeGreaterThan(0); const optional = interpolations.filter((inner) => !/^[A-Z0-9_]+:\?.+$/.test(inner)); expect(optional, 'переменные без :? — пустое значение молча попадёт в контейнер').toEqual([]); }); it('[PILOT-2] ни один сервис не запускается с NODE_ENV=development', () => { const offenders = Object.keys(compose.services).filter( (service) => environmentOf(service).NODE_ENV === 'development', ); expect(offenders).toEqual([]); }); it('[PILOT-3] у сервиса app нет учётных данных мигратора', () => { const env = environmentOf('app'); const keys = Object.keys(env).filter((key) => ['DATABASE_MIGRATION_URL', 'POSTGRES_MIGRATION_PASSWORD', 'POSTGRES_MIGRATION_USER'].includes( key, ), ); const values = Object.entries(env) .filter(([, value]) => /POSTGRES_MIGRATION_PASSWORD|krona_migrator/.test(value)) .map(([key]) => key); expect({ keys, values }).toEqual({ keys: [], values: [] }); }); });