| 1 | // Actual compiled image, same HostRoot/protocol/services, fake Engine authority. |
| 2 | // CI must name the image explicitly; normal source suites record a visible skip. |
| 3 | import { test } from 'node:test' |
| 4 | import assert from 'node:assert/strict' |
| 5 | import { execFileSync, spawn } from 'node:child_process' |
| 6 | import { existsSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' |
| 7 | import { createServer } from 'node:http' |
| 8 | import { tmpdir } from 'node:os' |
| 9 | import { join } from 'node:path' |
| 10 | import { activate, BUNDLE, sha256File, startHost } from './harness.mjs' |
| 11 | import { ErrorCode } from '../dist/protocol.mjs' |
| 12 | |
| 13 | const binary = process.env.CODEWHALE_COMPILED_HOST_TEST_BINARY |
| 14 | if (binary && !existsSync(binary)) throw new Error(`compiled image does not exist: ${binary}`) |
| 15 | const compiledTest = (name, run) => test(name, { skip: !binary && 'compiled image not requested' }, run) |
| 16 | const plugin = (source) => { |
| 17 | const dir = mkdtempSync(join(tmpdir(), 'cw-compiled-host-')) |
| 18 | const entry = join(dir, 'index.mjs') |
| 19 | writeFileSync(entry, source) |
| 20 | return { dir, entry, cleanup: () => rmSync(dir, { recursive: true, force: true }) } |
| 21 | } |
| 22 | const start = (options = {}) => startHost({ ...options, compiledHost: binary }) |
| 23 | |
| 24 | compiledTest('compiled identity and both trust tiers match canonical source', async (t) => { |
| 25 | const info = JSON.parse(execFileSync(binary, ['--codewhale-host-info'], { encoding: 'utf8', env: { ...process.env, BUN_OPTIONS: '', BUN_BE_BUN: '0' } })) |
| 26 | assert.equal(info.kind, 'codewhale-extension-host') |
| 27 | assert.equal(info.bundle_sha256, sha256File(BUNDLE)) |
| 28 | for (const tier of ['plugin', 'builtin']) { |
| 29 | const host = await start({ tier }) |
| 30 | try { |
| 31 | assert.equal(host.hello.bundle_sha256, info.bundle_sha256) |
| 32 | assert.deepEqual(host.hello.runtime, { name: 'bun', version: info.version }) |
| 33 | assert.equal(host.hello.tier, tier) |
| 34 | assert.ok(host.readyMs <= 1500, `ready ${host.readyMs}ms exceeds existing 1500ms gate`) |
| 35 | if (process.platform !== 'win32') { |
| 36 | const rss = Number(execFileSync('ps', ['-o', 'rss=', '-p', String(host.child.pid)], { encoding: 'utf8' }).trim()) / 1024 |
| 37 | assert.ok(rss <= 160, `idle ${rss}MiB exceeds existing 160MiB gate`) |
| 38 | t.diagnostic(`${tier}: ready ${host.readyMs.toFixed(1)}ms; RSS ${rss.toFixed(1)}MiB`) |
| 39 | } |
| 40 | } finally { await host.stop() } |
| 41 | } |
| 42 | }) |
| 43 | |
| 44 | compiledTest('compiled Native modules share services and cancellation withdraws owner', async (t) => { |
| 45 | const fixture = plugin(`import { Context } from '@deepseek-ai/cordis' |
| 46 | export const inject = ['tools'] |
| 47 | export function apply(ctx) { |
| 48 | if (!Context.is(ctx)) throw new Error('foreign Cordis') |
| 49 | ctx.tools.register({ name: 'held', description: '', parameters: { type: 'object', properties: {} }, execute(_input, call) { |
| 50 | return new Promise((resolve) => call.signal.addEventListener('abort', () => resolve('aborted'), { once: true })) |
| 51 | } }) |
| 52 | }`) |
| 53 | const host = await start() |
| 54 | t.after(async () => { await host.stop(); fixture.cleanup() }) |
| 55 | const { ref, result } = await activate(host, 'compiled-owner', fixture.entry) |
| 56 | assert.equal(result.status, 'ok', result.diagnostic) |
| 57 | const handle = host.registry.find((entry) => entry.op === 'register').handle |
| 58 | const call = host.request('tool/call', { handle, call_id: 'held', input: {}, deadline_ms: 5000 }) |
| 59 | setTimeout(() => host.cancel(call.id), 50) |
| 60 | await assert.rejects(call.promise, (error) => error.code === ErrorCode.Cancelled) |
| 61 | await host.call('ext/deactivate', { owner: ref, reason: 'test disposal' }) |
| 62 | assert.ok(host.registry.some((entry) => entry.op === 'unregister' && entry.handle === handle)) |
| 63 | await assert.rejects(host.call('tool/call', { handle, call_id: 'retired', input: {}, deadline_ms: 5000 })) |
| 64 | }) |
| 65 | |
| 66 | compiledTest('compiled launch ignores dotenv, bunfig and inherited runtime switches', async (t) => { |
| 67 | const fixture = plugin(`export const inject = ['tools'] |
| 68 | export function apply(ctx) { ctx.tools.register({ name: 'env', description: '', parameters: { type: 'object', properties: {} }, execute: () => JSON.stringify({ dotenv: process.env.CW_COMPILED_DOTENV, cli: process.env.BUN_BE_BUN, options: process.env.BUN_OPTIONS, execArgv: process.execArgv }) }) } |
| 69 | `) |
| 70 | writeFileSync(join(fixture.dir, '.env'), 'CW_COMPILED_DOTENV=should-not-load\n') |
| 71 | writeFileSync(join(fixture.dir, 'bunfig.toml'), 'preload = ["./missing-preload.mjs"]\n') |
| 72 | const host = await start({ cwd: fixture.dir, env: { BUN_BE_BUN: '1', BUN_OPTIONS: '--preload=missing-preload.mjs' } }) |
| 73 | t.after(async () => { await host.stop(); fixture.cleanup() }) |
| 74 | const { result } = await activate(host, 'env', fixture.entry) |
| 75 | assert.equal(result.status, 'ok', result.diagnostic) |
| 76 | const handle = host.registry.find((entry) => entry.op === 'register').handle |
| 77 | const value = await host.call('tool/call', { handle, call_id: 'env', input: {}, deadline_ms: 5000 }) |
| 78 | const expectedExecArgv = process.platform === 'win32' |
| 79 | // The Windows LPAC cannot open NUL; compile-host intentionally omits this flag there. |
| 80 | ? ['--no-install', '--no-env-file', '--no-addons'] |
| 81 | : ['--no-install', '--no-env-file', '--config=/dev/null', '--no-addons'] |
| 82 | assert.deepEqual(JSON.parse(value.content[0].text), { cli: '0', options: '', execArgv: expectedExecArgv }) |
| 83 | }) |
| 84 | |
| 85 | compiledTest('compiled Native imports cannot reach FFI or fresh worker realms', async (t) => { |
| 86 | const host = await start() |
| 87 | t.after(() => host.stop()) |
| 88 | for (const [name, source, pattern] of [ |
| 89 | ['ffi', "export async function apply() { const { dlopen } = await import('bun:ffi'); dlopen('/nonexistent/libc.so', {}) }", /bun:ffi.*not available/], |
| 90 | ['ffi-require', "import { createRequire } from 'node:module'; export function apply() { createRequire(import.meta.url)('bun:ffi').dlopen('/nonexistent/libc.so', {}) }", /bun:ffi.*not available/], |
| 91 | ['worker', "import { Worker } from 'node:worker_threads'; export function apply() { new Worker('0', { eval: true }) }", /Worker.*not available/], |
| 92 | ]) { |
| 93 | const fixture = plugin(source) |
| 94 | t.after(fixture.cleanup) |
| 95 | const { result } = await activate(host, name, fixture.entry) |
| 96 | assert.equal(result.status, 'failed') |
| 97 | assert.match(result.diagnostic, pattern) |
| 98 | } |
| 99 | }) |
| 100 | |
| 101 | compiledTest('compiled host refuses missing npm imports without registry traffic', async (t) => { |
| 102 | const requests = [] |
| 103 | const server = createServer((request, response) => { requests.push(request.url); response.statusCode = 404; response.end('{}') }) |
| 104 | await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)) |
| 105 | const url = `http://127.0.0.1:${server.address().port}/` |
| 106 | const fixture = plugin("import 'codewhale-compiled-missing-package-0101'; export function apply() {}") |
| 107 | const host = await start({ env: { BUN_CONFIG_REGISTRY: url, NPM_CONFIG_REGISTRY: url, BUN_INSTALL_CACHE_DIR: join(fixture.dir, 'cache') } }) |
| 108 | t.after(async () => { await host.stop(); fixture.cleanup(); await new Promise((resolve) => server.close(resolve)) }) |
| 109 | const { result } = await activate(host, 'missing', fixture.entry) |
| 110 | assert.equal(result.status, 'failed') |
| 111 | assert.match(result.diagnostic, /Cannot find package.*codewhale-compiled-missing-package/) |
| 112 | assert.deepEqual(requests, []) |
| 113 | const bun = process.env.CODEWHALE_BUN_TEST_BINARY |
| 114 | assert.ok(bun, 'compiled qualification must name its local Bun control binary') |
| 115 | const control = spawn(bun, [fixture.entry], { env: { ...process.env, BUN_OPTIONS: '', BUN_BE_BUN: '0', BUN_CONFIG_REGISTRY: url, NPM_CONFIG_REGISTRY: url, BUN_INSTALL_CACHE_DIR: join(fixture.dir, 'cache') }, stdio: 'ignore' }) |
| 116 | await new Promise((resolve, reject) => { |
| 117 | const timer = setTimeout(() => { control.kill(); reject(new Error('local-registry control timed out')) }, 5000) |
| 118 | control.on('error', (error) => { clearTimeout(timer); reject(error) }) |
| 119 | control.on('exit', () => { clearTimeout(timer); resolve() }) |
| 120 | }) |
| 121 | assert.ok(requests.length > 0, 'without --no-install the same missing import must reach the local control registry') |
| 122 | }) |
| 123 | |
| 124 | // Five direct-image cases apply on every supported OS. This additional macOS |
| 125 | // reexec probe is registered only where it applies. All platforms separately |
| 126 | // require actual compiled-image memory enforcement in the Rust Native receipt. |
| 127 | if (process.platform === 'darwin') compiledTest('compiled macOS reexec keeps PID and kernel kills memory overflow', async (t) => { |
| 128 | const fixture = plugin(`export const inject = ['tools'] |
| 129 | export function apply(ctx) { |
| 130 | ctx.tools.register({ name: 'pid', description: '', parameters: { type: 'object', properties: {} }, execute: () => String(process.pid) }) |
| 131 | ctx.tools.register({ name: 'hog', description: '', parameters: { type: 'object', properties: {} }, async execute() { const chunks = []; for (let i = 0; i < 32; i++) { chunks.push(Buffer.alloc(64 * 1024 * 1024, 1)); await new Promise((resolve) => setTimeout(resolve, 5)) }; return String(chunks.length) } }) |
| 132 | }`) |
| 133 | const host = await start({ env: { CODEWHALE_HOST_MEMORY_LIMIT_MIB: '300' } }) |
| 134 | t.after(async () => { await host.stop(); fixture.cleanup() }) |
| 135 | assert.equal(host.hello.memory_limit_mib, 300) |
| 136 | const { result } = await activate(host, 'memory', fixture.entry) |
| 137 | assert.equal(result.status, 'ok', result.diagnostic) |
| 138 | const [pid, hog] = host.registry.filter((entry) => entry.op === 'register').map((entry) => entry.handle) |
| 139 | const value = await host.call('tool/call', { handle: pid, call_id: 'pid', input: {}, deadline_ms: 5000 }) |
| 140 | assert.equal(Number(value.content[0].text), host.child.pid) |
| 141 | host.request('tool/call', { handle: hog, call_id: 'hog', input: {}, deadline_ms: 30000 }) |
| 142 | let timer |
| 143 | const ended = await Promise.race([host.exit, new Promise((resolve) => { timer = setTimeout(() => resolve('still running'), 20000) })]) |
| 144 | clearTimeout(timer) |
| 145 | assert.deepEqual(ended, { code: null, signal: 'SIGKILL' }) |
| 146 | }) |
| 147 |