fix(feishu): honor proxy settings for REST and WebSocket

This commit is contained in:
xmanrui 2026-08-22 14:45:25 +08:00
parent b9ceac0779
commit f7d2fe7047
14 changed files with 467 additions and 188 deletions

View file

@ -2,24 +2,23 @@ import assert from 'node:assert/strict';
import test from 'node:test';
import { verifyFeishuApp } from '../../../src/channels/feishu/feishu-app.mjs';
function response(body, ok = true, status = 200) {
return { ok, status, async json() { return body; } };
}
test('verifyFeishuApp validates credentials and returns a safe bot identity', async () => {
const requests = [];
const result = await verifyFeishuApp({
appId: 'cli_test',
appSecret: 'never-return-this',
fetchImpl: async (url, options) => {
requests.push({ url: String(url), options });
if (requests.length === 1) {
return response({ code: 0, tenant_access_token: 'tenant-token' });
}
return response({
code: 0,
bot: { app_name: '北汇星河助手', open_id: 'ou_bot', activate_status: 1 },
});
timeoutMs: 1234,
httpInstance: {
async request(options) {
requests.push(options);
if (requests.length === 1) {
return { code: 0, tenant_access_token: 'tenant-token' };
}
return {
code: 0,
bot: { app_name: '北汇星河助手', open_id: 'ou_bot', activate_status: 1 },
};
},
},
});
@ -30,8 +29,16 @@ test('verifyFeishuApp validates credentials and returns a safe bot identity', as
activated: 1,
});
assert.equal('appSecret' in result, false);
assert.match(requests[0].options.body, /never-return-this/);
assert.equal(requests[1].options.headers.authorization, 'Bearer tenant-token');
assert.equal(requests[0].method, 'POST');
assert.equal(requests[0].url, 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal');
assert.deepEqual(requests[0].data, { app_id: 'cli_test', app_secret: 'never-return-this' });
assert.equal(requests[0].timeout, 1234);
assert.ok(requests[0].signal instanceof AbortSignal);
assert.equal(requests[1].method, 'GET');
assert.equal(requests[1].url, 'https://open.feishu.cn/open-apis/bot/v3/info/');
assert.equal(requests[1].headers.authorization, 'Bearer tenant-token');
assert.equal(requests[1].timeout, 1234);
assert.ok(requests[1].signal instanceof AbortSignal);
});
test('verifyFeishuApp rejects invalid credentials before reading bot info', async () => {
@ -39,10 +46,19 @@ test('verifyFeishuApp rejects invalid credentials before reading bot info', asyn
await assert.rejects(verifyFeishuApp({
appId: 'cli_bad',
appSecret: 'bad',
fetchImpl: async () => {
calls += 1;
return response({ code: 10003, msg: 'invalid app secret' });
httpInstance: {
async request() {
calls += 1;
return { code: 10003, msg: 'invalid app secret' };
},
},
}), /invalid app secret/);
assert.equal(calls, 1);
});
test('verifyFeishuApp requires the shared SDK HTTP instance', async () => {
await assert.rejects(verifyFeishuApp({
appId: 'cli_test',
appSecret: 'secret',
}), /requires an HTTP instance/);
});