import { afterEach, beforeEach, describe, expect, test } from 'bun:test'; import { existsSync } from 'node:fs'; import { rm } from 'node:fs/promises'; import { type DbClient, createDbClient } from '../db/client'; import { moduleConfigs, modules } from '../db/schema'; import { extractTargetHost } from './deploy-planner'; const TEST_DB_PATH = './test-deploy-planner.db'; /** * Regression for the malformed SSH target bug (ISS-0019): extractTargetHost * read module_configs.valueJson RAW. valueJson is JSON-ENCODED — a string is * stored as `"10.0.20.13/24"` (with quotes) — so splitting on '/' kept the * leading quote, producing `root@"10.0.20.13` and a 180s SSH-wait timeout * against a container that was actually up. It must parse valueJson. */ describe('extractTargetHost', () => { let db: DbClient; beforeEach(() => { db = createDbClient({ path: TEST_DB_PATH }); db.insert(modules) .values({ id: 'apt-repo', name: 'apt-repo', version: '1.0.0', manifestData: {}, sourcePath: '/tmp/apt-repo', }) .run(); }); afterEach(async () => { db.$client.close(); for (const suffix of ['', '-shm', '-wal']) { const p = `${TEST_DB_PATH}${suffix}`; if (existsSync(p)) await rm(p); } }); function setConfig(key: string, value: string): void { db.insert(moduleConfigs) .values({ moduleId: 'apt-repo', key, value, valueJson: JSON.stringify(value) }) .run(); } test('strips the CIDR from a JSON-encoded target_ip without keeping the quote', async () => { setConfig('hostname', 'apt.celilo.computer'); setConfig('target_ip', '10.0.20.13/24'); const host = await extractTargetHost('apt-repo', db); expect(host.ip).toBe('10.0.20.13'); // not `"10.0.20.13` expect(host.ip).not.toContain('"'); expect(host.hostname).toBe('apt.celilo.computer'); expect(host.user).toBe('root'); }); test('honors ansible_user and falls back through ip.primary', async () => { setConfig('ip.primary', '203.0.113.7'); setConfig('ansible_user', 'peba'); const host = await extractTargetHost('apt-repo', db); expect(host.ip).toBe('203.0.113.7'); expect(host.user).toBe('peba'); }); });