feat(gateway): add node capability negotiation foundation
This commit is contained in:
@@ -577,3 +577,86 @@ describe('GatewayServer WebSocket ingress rate limiting', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('GatewayServer node registration and capability negotiation', () => {
|
||||
const NODE_PORT = 18894;
|
||||
let nodeServer: GatewayServer;
|
||||
|
||||
beforeAll(async () => {
|
||||
if (!LISTEN_ALLOWED) {
|
||||
return;
|
||||
}
|
||||
nodeServer = new GatewayServer({
|
||||
port: NODE_PORT,
|
||||
sessionManager: mockSessionManager as unknown as GatewayServerConfig['sessionManager'],
|
||||
modelClient: mockModelClient,
|
||||
systemPrompt: 'Test prompt',
|
||||
toolRegistry: mockToolRegistry as unknown as GatewayServerConfig['toolRegistry'],
|
||||
toolExecutor: mockToolExecutor as unknown as GatewayServerConfig['toolExecutor'],
|
||||
uiDir: resolve(import.meta.dirname, 'ui'),
|
||||
nodes: {
|
||||
enabled: true,
|
||||
allowedRoles: ['companion'],
|
||||
featureGates: { 'ui.canvas': true },
|
||||
},
|
||||
});
|
||||
await nodeServer.start();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
if (!LISTEN_ALLOWED) {
|
||||
return;
|
||||
}
|
||||
await nodeServer.stop();
|
||||
});
|
||||
|
||||
it('enforces role allow/deny and node registration lifecycle', async () => {
|
||||
if (!LISTEN_ALLOWED) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ws = await new Promise<WebSocket>((resolve, reject) => {
|
||||
const c = new WebSocket(`ws://127.0.0.1:${NODE_PORT}`);
|
||||
c.on('open', () => resolve(c));
|
||||
c.on('error', reject);
|
||||
});
|
||||
|
||||
try {
|
||||
const beforeRegister = await sendAndReceive(ws, { id: 1, method: 'node.capabilities.get', params: {} });
|
||||
expect((beforeRegister as GatewayError).error.code).toBe(ErrorCode.AuthFailed);
|
||||
|
||||
const badRole = await sendAndReceive(ws, {
|
||||
id: 2,
|
||||
method: 'node.register',
|
||||
params: {
|
||||
nodeId: 'node-bad',
|
||||
role: 'observer',
|
||||
protocolVersion: 1,
|
||||
capabilities: ['ui.canvas'],
|
||||
},
|
||||
});
|
||||
expect((badRole as GatewayError).error.code).toBe(ErrorCode.AuthFailed);
|
||||
|
||||
const registered = await sendAndReceive(ws, {
|
||||
id: 3,
|
||||
method: 'node.register',
|
||||
params: {
|
||||
nodeId: 'node-good',
|
||||
role: 'companion',
|
||||
protocolVersion: 1,
|
||||
capabilities: ['ui.canvas'],
|
||||
},
|
||||
});
|
||||
expect((registered as GatewayResponse).id).toBe(3);
|
||||
expect(((registered as GatewayResponse).result as { registered: boolean }).registered).toBe(true);
|
||||
|
||||
const capabilities = await sendAndReceive(ws, { id: 4, method: 'node.capabilities.get', params: {} });
|
||||
expect((capabilities as GatewayResponse).id).toBe(4);
|
||||
expect(((capabilities as GatewayResponse).result as { node: { role: string } }).node.role).toBe('companion');
|
||||
} finally {
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
ws.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user