/** * celilo's fleet SSH keypair, minted by the framework rather than by * celilo-mgmt's on_install (design D9b of * openspec/changes/hook-process-boundary). */ import { afterEach, beforeEach, describe, expect, it } from 'bun:test'; import { execFileSync } from 'node:child_process'; import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { resetTestDbPath } from '../test-utils/db-path'; import { ensureFleetKey, findFleetPrivateKey, getFleetSshDir } from './fleet-key'; describe('ensureFleetKey', () => { let dataDir: string; beforeEach(() => { dataDir = mkdtempSync(join(tmpdir(), 'celilo-fleet-key-')); process.env.CELILO_DB_PATH = join(dataDir, 'celilo.db'); }); afterEach(() => { resetTestDbPath(); rmSync(dataDir, { recursive: true, force: true }); }); it('mints an ed25519 keypair next to the DB and returns the public half', () => { const key = ensureFleetKey(); expect(key.created).toBe(true); expect(key.publicKey.startsWith('ssh-ed25519 ')).toBe(true); expect(existsSync(join(dataDir, '.ssh', 'id_ed25519'))).toBe(true); expect(readFileSync(join(dataDir, '.ssh', 'id_ed25519.pub'), 'utf-8').trim()).toBe( key.publicKey, ); expect(getFleetSshDir()).toBe(join(dataDir, '.ssh')); }); it('reuses an existing key instead of re-keying', () => { const first = ensureFleetKey(); const second = ensureFleetKey(); // Re-keying would strand every machine whose authorized_keys holds the // old public half, and a redeploy calls this every time. expect(second.created).toBe(false); expect(second.publicKey).toBe(first.publicKey); }); }); describe('findFleetPrivateKey', () => { let dataDir: string; let homeDir: string; let realHome: string | undefined; beforeEach(() => { dataDir = mkdtempSync(join(tmpdir(), 'celilo-fleet-find-')); homeDir = mkdtempSync(join(tmpdir(), 'celilo-fleet-home-')); process.env.CELILO_DB_PATH = join(dataDir, 'celilo.db'); realHome = process.env.HOME; process.env.HOME = homeDir; }); afterEach(() => { resetTestDbPath(); process.env.HOME = realHome; rmSync(dataDir, { recursive: true, force: true }); rmSync(homeDir, { recursive: true, force: true }); }); /** A second, unrelated keypair in $HOME/.ssh, as every real box has. */ function plantHomeKey(): string { const dir = join(homeDir, '.ssh'); mkdirSync(dir, { recursive: true, mode: 0o700 }); const path = join(dir, 'id_ed25519'); execFileSync('ssh-keygen', ['-t', 'ed25519', '-N', '', '-f', path, '-C', 'someone-else'], { stdio: 'pipe', }); return readFileSync(`${path}.pub`, 'utf-8').trim(); } it('finds the key celilo minted, even when $HOME holds a different one', () => { // This is celilo#1240. `ensureFleetKey` mints into the data dir and // `machine add` searched $HOME only, so a fleet whose key celilo minted // could not add a machine without --ssh-key-file. The e2e management // container has both directories populated with DIFFERENT keys, which is // why it failed there and not on a developer's box. const homePublicKey = plantHomeKey(); const fleet = ensureFleetKey(); expect(fleet.publicKey).not.toBe(homePublicKey); const found = findFleetPrivateKey(fleet.publicKey); expect(found).toBe(join(dataDir, '.ssh', 'id_ed25519')); }); it('still finds a key that only lives in $HOME', () => { // The auto-detected case: `initializeSystem` reads $HOME/.ssh when // ssh.public_key is unset, and that fleet must keep working. const homePublicKey = plantHomeKey(); expect(findFleetPrivateKey(homePublicKey)).toBe(join(homeDir, '.ssh', 'id_ed25519')); }); it('returns null when no private key matches the recorded public half', () => { plantHomeKey(); const orphan = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA nobody'; expect(findFleetPrivateKey(orphan)).toBeNull(); }); });