This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { Hono } from 'hono';
|
||||
import type { Principal } from '../src/lib/auth';
|
||||
import type { ApiEnv } from '../src/lib/mutation';
|
||||
import { createPiggyChatRoutes } from '../src/routes/piggy-chat';
|
||||
|
||||
const principal: Principal = {
|
||||
userId: '10000000-0000-4000-8000-000000000001',
|
||||
email: 'member@example.com',
|
||||
name: 'Member',
|
||||
isPlatformAdmin: false,
|
||||
teams: [{ team: 'demand', role: 'member' }],
|
||||
via: 'jwt',
|
||||
scopes: ['read', 'write'],
|
||||
};
|
||||
|
||||
function appFor(fetchImpl: typeof fetch, identity: Principal = principal) {
|
||||
const app = new Hono<ApiEnv>();
|
||||
app.use('*', async (context, next) => {
|
||||
context.set('principal', identity);
|
||||
await next();
|
||||
});
|
||||
app.route(
|
||||
'/',
|
||||
createPiggyChatRoutes({
|
||||
enabled: true,
|
||||
internalUrl: 'http://127.0.0.1:8931',
|
||||
internalToken: 'internal-token-with-at-least-32-characters',
|
||||
fetchImpl,
|
||||
}),
|
||||
);
|
||||
return app;
|
||||
}
|
||||
|
||||
test('the authenticated proxy forwards bounded identity and relays NDJSON unchanged', async () => {
|
||||
let forwarded: Record<string, unknown> | undefined;
|
||||
const fetchImpl: typeof fetch = async (input, init) => {
|
||||
assert.equal(String(input), 'http://127.0.0.1:8931/internal/chat');
|
||||
assert.equal(
|
||||
new Headers(init?.headers).get('authorization'),
|
||||
'Bearer internal-token-with-at-least-32-characters',
|
||||
);
|
||||
forwarded = JSON.parse(String(init?.body)) as Record<string, unknown>;
|
||||
return new Response(
|
||||
`${JSON.stringify({ type: 'content_delta', delta: 'Scoped answer' })}\n` +
|
||||
`${JSON.stringify({ type: 'done', inputTokens: 2, outputTokens: 3 })}\n`,
|
||||
{ status: 200, headers: { 'content-type': 'application/x-ndjson' } },
|
||||
);
|
||||
};
|
||||
const app = appFor(fetchImpl);
|
||||
const response = await app.request('/api/piggy/chat', {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
message: 'Summarise this contract.',
|
||||
context: {
|
||||
type: 'contract',
|
||||
id: '20000000-0000-4000-8000-000000000002',
|
||||
label: 'Order form',
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
assert.equal(response.status, 200);
|
||||
assert.match(response.headers.get('content-type') ?? '', /application\/x-ndjson/);
|
||||
assert.deepEqual(forwarded, {
|
||||
principalUserId: principal.userId,
|
||||
message: 'Summarise this contract.',
|
||||
context: {
|
||||
type: 'contract',
|
||||
id: '20000000-0000-4000-8000-000000000002',
|
||||
label: 'Order form',
|
||||
},
|
||||
});
|
||||
assert.equal(
|
||||
await response.text(),
|
||||
`${JSON.stringify({ type: 'content_delta', delta: 'Scoped answer' })}\n` +
|
||||
`${JSON.stringify({ type: 'done', inputTokens: 2, outputTokens: 3 })}\n`,
|
||||
);
|
||||
});
|
||||
|
||||
test('a credential without read scope never reaches the internal service', async () => {
|
||||
let fetched = false;
|
||||
const app = appFor(
|
||||
async () => {
|
||||
fetched = true;
|
||||
return new Response();
|
||||
},
|
||||
{ ...principal, scopes: ['write'] },
|
||||
);
|
||||
const response = await app.request('/api/piggy/chat', {
|
||||
method: 'POST',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
body: JSON.stringify({ message: 'Read the book.' }),
|
||||
});
|
||||
assert.equal(response.status, 403);
|
||||
assert.equal(fetched, false);
|
||||
});
|
||||
Reference in New Issue
Block a user