import assert from 'node:assert/strict'; import { EventEmitter } from 'node:events'; import fs from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; import test from 'node:test'; import { createAiderExecutorAdapter, createGoosedExecutorAdapter, createOpenHandsExecutorAdapter, } from './executor-adapters.mjs'; function request(executor = 'goosed') { return { executor, task: { instruction: 'Fix the validation', workspaceRef: { kind: 'workspace-alias', id: 'canary' }, }, }; } function sseResponse(events) { const encoder = new TextEncoder(); const body = new ReadableStream({ start(controller) { for (const event of events) { controller.enqueue(encoder.encode( `event: ${event.type}\ndata: ${JSON.stringify(event.data)}\n\n`, )); } controller.close(); }, }); return new Response(body, { status: 200, headers: { 'content-type': 'text/event-stream' }, }); } test('Goosed adapter uses the current session API, streams bounded metadata and returns refs', async () => { const calls = []; const emitted = []; const adapter = createGoosedExecutorAdapter({ baseUrl: 'http://127.0.0.1:18006', secret: 'secret', workspaceResolver: async () => '/tmp/canary', fetchImpl: async (url, init) => { calls.push({ url, init }); if (url.endsWith('/agent/start')) { return Response.json({ id: 'session-1' }); } if (url.endsWith('/events')) { return sseResponse([ { type: 'message', data: { type: 'message', secret: 'not-projected' } }, { type: 'finish', data: { type: 'finish' } }, ]); } if (url.endsWith('/reply')) return Response.json({ ok: true }); throw new Error(`Unexpected URL: ${url}`); }, }); const result = await adapter.submit(request(), { jobId: 'job-1', emit: async (type, data) => emitted.push({ type, data }), }); assert.deepEqual(result.artifactRefs, [{ kind: 'goosed-session', id: 'session-1' }]); assert.equal(result.metrics.eventCount, 2); assert.equal(calls[0].url, 'http://127.0.0.1:18006/agent/start'); assert.equal(calls[0].init.headers['X-Secret-Key'], 'secret'); assert.equal(JSON.parse(calls[0].init.body).working_dir, '/tmp/canary'); assert.equal( JSON.parse(calls.find((call) => call.url.endsWith('/reply')).init.body) .user_message.content[0].text, 'Fix the validation', ); assert.deepEqual( emitted.map((event) => event.type), [ 'executor_job_session_created', 'executor_job_adapter_event', 'executor_job_adapter_event', ], ); assert.equal(JSON.stringify(emitted).includes('not-projected'), false); }); test('Goosed adapter rejects remote targets unless explicitly allowed', () => { assert.throws( () => createGoosedExecutorAdapter({ baseUrl: 'https://executor.example.com' }), /explicit allowRemote/, ); assert.doesNotThrow( () => createGoosedExecutorAdapter({ baseUrl: 'https://executor.example.com', allowRemote: true, }), ); assert.throws( () => createGoosedExecutorAdapter({ baseUrl: 'https://executor.example.com', allowRemote: true, tlsInsecure: true, }), /restricted to local targets/, ); assert.doesNotThrow( () => createGoosedExecutorAdapter({ baseUrl: 'https://host.docker.internal:18006', allowRemote: true, tlsInsecure: true, }), ); }); test('Aider process adapter resolves a workspace alias and never invokes a shell', async () => { const root = await fs.mkdtemp(path.join(os.tmpdir(), 'memind-executor-')); const workspace = path.join(root, 'canary'); await fs.mkdir(workspace); const spawnCalls = []; const emitted = []; const spawnImpl = (command, args, options) => { spawnCalls.push({ command, args, options }); const child = new EventEmitter(); child.stdout = new EventEmitter(); child.stderr = new EventEmitter(); child.kill = () => {}; queueMicrotask(() => { child.stdout.emit('data', Buffer.from('done')); child.emit('exit', 0, null); }); return child; }; try { const adapter = createAiderExecutorAdapter({ command: '/usr/local/bin/aider', allowedRoot: root, workspaceAliases: { canary: workspace }, spawnImpl, }); const result = await adapter.submit(request('aider'), { jobId: 'job-1', emit: async (type, data) => emitted.push({ type, data }), }); assert.equal(result.outcome, 'completed'); assert.deepEqual(result.artifactRefs, [{ kind: 'workspace-alias', id: 'canary' }]); assert.equal(spawnCalls[0].options.cwd, await fs.realpath(workspace)); assert.equal(spawnCalls[0].options.shell, false); assert.deepEqual( spawnCalls[0].args, ['--yes-always', '--message', 'Fix the validation'], ); assert.equal(emitted[0].data.stream, 'stdout'); assert.equal('HOME' in spawnCalls[0].options.env, false); } finally { await fs.rm(root, { recursive: true, force: true }); } }); test('OpenHands adapter refuses workspace aliases outside its isolated root', async () => { const root = await fs.mkdtemp(path.join(os.tmpdir(), 'memind-executor-root-')); const outside = await fs.mkdtemp(path.join(os.tmpdir(), 'memind-executor-outside-')); try { const adapter = createOpenHandsExecutorAdapter({ command: '/usr/local/bin/openhands', allowedRoot: root, workspaceAliases: { canary: outside }, }); await assert.rejects( adapter.submit(request('openhands'), { jobId: 'job-1' }), (error) => error.code === 'EXECUTOR_WORKSPACE_OUTSIDE_ROOT', ); } finally { await fs.rm(root, { recursive: true, force: true }); await fs.rm(outside, { recursive: true, force: true }); } });