/** * bin/lemon.js — commit b7b5096(全站鉴权)之后,agent-chat.js 挂了 requireAuthOrInternal, * 这个 CLI 跑在 agent 自己的 claude CLI 子进程里,没有登录 cookie,只能靠父进程通过 * process.env 传下来的 LEMON_INTERNAL_TOKEN 过 internal 校验(server/middleware/jwt-auth.js)。 * * 用一个假的 HTTP 服务器代替真实后端,只验证 bin/lemon.js 发请求时带没带这个 header。 */ import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import http from 'http'; import { execFile } from 'child_process'; import path from 'path'; const LEMON_BIN = path.resolve(__dirname, '../../../bin/lemon.js'); let server, port, lastHeaders; function runLemon(args, env) { return new Promise((resolve) => { execFile('node', [LEMON_BIN, ...args], { env }, () => resolve()); }); } describe('bin/lemon.js — LEMON_INTERNAL_TOKEN 透传', () => { beforeAll(async () => { server = http.createServer((req, res) => { lastHeaders = req.headers; res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ok: true })); }); // 用随机端口,避免跟本机真实跑着的 3010 dev server 撞车(LEMON_API_BASE 让 bin/lemon.js 指过来) await new Promise((resolve) => server.listen(0, resolve)); port = server.address().port; }); afterAll(() => new Promise((resolve) => server.close(resolve))); it('设了 LEMON_INTERNAL_TOKEN 时,请求头带上 x-internal-token', async () => { await runLemon( ['task', 'report', '--taskId', 't1', '--from', 'a', '--to', 'b'], { ...process.env, LEMON_API_BASE: `http://localhost:${port}/api`, LEMON_INTERNAL_TOKEN: 'test-token-abc' } ); expect(lastHeaders['x-internal-token']).toBe('test-token-abc'); }); it('没设 LEMON_INTERNAL_TOKEN 时,不带这个 header(不伪造身份)', async () => { const env = { ...process.env, LEMON_API_BASE: `http://localhost:${port}/api` }; delete env.LEMON_INTERNAL_TOKEN; await runLemon(['task', 'report', '--taskId', 't1', '--from', 'a', '--to', 'b'], env); expect(lastHeaders['x-internal-token']).toBeUndefined(); }); });