import { describe, expect, test } from 'bun:test'; import { existsSync, mkdtempSync, readFileSync, readdirSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { findMonorepoRoot } from './repo-root'; /** * A suite that has to package a module mid-run does it with the HOST's celilo: * `bun run apps/celilo/src/cli/index.ts package `. `package` signs with a * master key, and with nothing set that key is the host's own, the operator's * on a developer or gate machine, created there if there is none. * * celilo now refuses to resolve its default data directory under a test run * (celilo#1512), and a suite is one: the child inherits NODE_ENV=test. So the * harness hands that child a key of its own. These run the real command the way * the harness does, under a stand-in home, and look at what the home holds. */ const repoRoot = findMonorepoRoot(join(import.meta.dir, '..')); const cli = repoRoot ? join(repoRoot, 'apps/celilo/src/cli/index.ts') : ''; // Small, and it has no build step, so packaging it is a copy and a signature. const moduleDir = repoRoot ? join(repoRoot, 'modules/hello-trespass') : ''; function packageAsASuiteDoes(extraEnv: Record) { const work = mkdtempSync(join(tmpdir(), 'celilo-suite-package-')); const home = join(work, 'home'); const env: Record = { ...process.env, NODE_ENV: 'test', HOME: home, ...extraEnv, }; for (const key of ['CELILO_DATA_DIR', 'CELILO_DB_PATH', 'EVENT_BUS_DB', 'XDG_DATA_HOME']) { delete env[key]; } if (!('CELILO_MASTER_KEY_PATH' in extraEnv)) env.CELILO_MASTER_KEY_PATH = undefined; const out = join(work, 'out.netapp'); const child = Bun.spawnSync( [process.execPath, 'run', cli, 'package', moduleDir, '--output', out], { env, stdin: 'ignore', timeout: 120_000, }, ); const celiloStateInHome = [ 'Library/Application Support/celilo', '.local/share/celilo', '.celilo', ].filter((path) => existsSync(join(home, path))); const result = { exitCode: child.exitCode, output: `${child.stdout.toString()}${child.stderr.toString()}`, packaged: existsSync(out), celiloStateInHome, work, }; return result; } describe.skipIf(!repoRoot)('the key an in-run `celilo package` signs with', () => { test('with the harness’s own key path it packages, and the home is left alone', () => { const key = join(mkdtempSync(join(tmpdir(), 'celilo-suite-key-')), 'signing.key'); const run = packageAsASuiteDoes({ CELILO_MASTER_KEY_PATH: key }); try { expect(run.output).not.toContain('Refusing'); expect(run.exitCode).toBe(0); expect(run.packaged).toBe(true); expect(existsSync(key)).toBe(true); expect(run.celiloStateInHome).toEqual([]); } finally { rmSync(run.work, { recursive: true, force: true }); } }, 150_000); test('without one, celilo refuses rather than reach for the host’s key', () => { // The state the harness was in. This is why the env below is not optional. const run = packageAsASuiteDoes({}); try { expect(run.exitCode).not.toBe(0); expect(run.output).toContain('celilo#1512'); expect(run.packaged).toBe(false); expect(run.celiloStateInHome).toEqual([]); } finally { rmSync(run.work, { recursive: true, force: true }); } }, 150_000); test('the harness passes that key path to the command it runs', () => { const src = readFileSync(join(import.meta.dir, 'container-manager.ts'), 'utf-8'); const call = /run\(\s*`bun run \$\{JSON\.stringify\(celiloCliPath\)\} package [\s\S]*?\n {12}\);/.exec( src, ); expect(call).not.toBeNull(); expect(call?.[0]).toContain('CELILO_MASTER_KEY_PATH: SUITE_PACKAGE_KEY_PATH'); expect(call?.[0]).toContain('...process.env'); // And the fixture these tests package really is a module. expect(readdirSync(moduleDir)).toContain('manifest.yml'); }); });