agent-chat-company-gate.test.js
3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**
* agent-chat-company-gate.test.js —— 38 号文档 Phase 3
*
* agent-chat.js(/api/agent/*)一直靠 :agentId 里的命名空间前缀("{companyId}:{role}",
* locator.companyStateDir 解析)区分会话属于哪家公司,但 Phase 1/2 都没顾上这个文件的
* 归属校验——只要求登录,没查公司归不归当前用户。真实 curl 验证过是可以跨租户读会话的
* (GET .../conversations 对不是自己公司的 companyId:role 依然 200)。
*
* 补的是 router.param('agentId', ...):这里直接拿 Express 暴露的 `router.params.agentId`
* 数组单元测(不发真实 HTTP、不起 server),比照 company.js 那道 companyId 收口的判据
* canAccessCompany,行为应该完全对称。
*/
process.env.LEMONBOSS_CLAUDE_MODE = 'mock'; // 必须在 require 路由之前
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import path from 'path';
const REPO_ROOT = path.resolve(__dirname, '../../..');
const { ensureTestCompany, removeTestCompany } = require('../helpers/ensure-test-company');
const agentChatRouter = require('../../routes/agent-chat.js');
const paramHandler = agentChatRouter.params.agentId[0];
const OWNER = { id: 9001, role: 'user' };
const OTHER = { id: 9002, role: 'user' };
const ADMIN = { id: 9003, role: 'admin' };
const INTERNAL = { id: 0, role: 'system', internal: true };
const CID = 'gate-test-co';
function runParam(agentId, user) {
return new Promise((resolve) => {
const req = { user };
const res = {
_status: null,
status(code) { this._status = code; return this; },
json(body) { resolve({ status: this._status, body }); },
};
const next = (err) => resolve({ status: null, next: err || true });
paramHandler(req, res, next, agentId);
});
}
describe('agent-chat.js 的 :agentId 归属校验(38 号文档 Phase 3)', () => {
beforeAll(() => {
ensureTestCompany(CID, { ownerId: OWNER.id });
});
afterAll(() => {
removeTestCompany(CID);
});
it('公司自己的用户能过(next 被调用,不是 404)', async () => {
const r = await runParam(`${CID}:some-role`, OWNER);
expect(r.next).toBe(true);
});
it('别的登录用户访问 → 404(不暴露这个公司/agent 存在)', async () => {
const r = await runParam(`${CID}:some-role`, OTHER);
expect(r.status).toBe(404);
expect(r.body.error).toMatch(/不存在/);
});
it('admin 不受归属限制', async () => {
const r = await runParam(`${CID}:some-role`, ADMIN);
expect(r.next).toBe(true);
});
it('公司不存在 → 404(不是 next 放行)', async () => {
const r = await runParam('no-such-company:role', OWNER);
expect(r.status).toBe(404);
});
it('没有 companyId 前缀的全局 agent(如 master)不做归属校验,任何登录用户都放行', async () => {
const r = await runParam('master', OTHER);
expect(r.next).toBe(true);
});
it('内部自环调用(req.user.internal)直接放行,不查归属', async () => {
const r = await runParam(`${CID}:some-role`, INTERNAL);
expect(r.next).toBe(true);
const r2 = await runParam('no-such-company:role', INTERNAL);
expect(r2.next).toBe(true);
});
});