gateway-delegation-proxy.test.mjs
105 lines 3.7 KB
Raw
sha256:b5f647cb9c409f563d4671fe3fc05ddea01fabfed9b41fc11cb923588e1c1baf mirror: GitHub Phase A durable MCP OAuth (#270) Human minor ⚠ breaking 10 days ago
1 /**
2 * Gateway → bridge delegation route proxy contract (Phase 7C-L1).
3 *
4 * Locks in proxy wiring so hosted gateway forwards delegation REST to bridge,
5 * mirroring calendar/flow hosted parity pattern.
6 */
7
8 import fs from 'node:fs';
9 import { test } from 'node:test';
10 import assert from 'node:assert/strict';
11 import http from 'http';
12 import express from 'express';
13 import crypto from 'crypto';
14 import path from 'path';
15 import { fileURLToPath, pathToFileURL } from 'url';
16
17 const __dirname = path.dirname(fileURLToPath(import.meta.url));
18 const projectRoot = path.resolve(__dirname, '..');
19
20 const SECRET = 'gateway-delegation-proxy-test-secret-32chars';
21
22 function signTestJwt(payload) {
23 const header = Buffer.from(JSON.stringify({ alg: 'HS256', typ: 'JWT' })).toString('base64url');
24 const body = Buffer.from(JSON.stringify(payload)).toString('base64url');
25 const data = `${header}.${body}`;
26 const sig = crypto.createHmac('sha256', SECRET).update(data).digest('base64url');
27 return `${data}.${sig}`;
28 }
29
30 function startMockBridge(mockBridge) {
31 const srv = http.createServer(mockBridge);
32 return new Promise((resolve, reject) => {
33 srv.listen(0, '127.0.0.1', (err) => {
34 if (err) return reject(err);
35 const port = srv.address().port;
36 resolve({
37 bridgeUrl: `http://127.0.0.1:${port}`,
38 close: () => new Promise((r) => srv.close(() => r())),
39 });
40 });
41 });
42 }
43
44 test('gateway proxies POST /api/v1/delegation/grants to bridge with auth headers', async (t) => {
45 const calls = [];
46 const mockBridge = express();
47 mockBridge.use(express.json());
48 mockBridge.post('/api/v1/delegation/grants', (req, res) => {
49 calls.push({
50 method: req.method,
51 url: req.originalUrl,
52 auth: req.headers.authorization,
53 vault: req.headers['x-vault-id'],
54 body: req.body,
55 });
56 res.status(201).json({
57 schema: 'knowtation.delegation_grant_mint/v0',
58 grant: { grant_id: 'dgrnt_test01', consent_id: req.body?.consent_id },
59 bearer: 'dgrnt_bearer_test_only',
60 });
61 });
62
63 const { bridgeUrl, close } = await startMockBridge(mockBridge);
64 t.after(close);
65
66 process.env.NETLIFY = '1';
67 process.env.CANISTER_URL = 'http://canister.placeholder.test';
68 process.env.SESSION_SECRET = SECRET;
69 process.env.BRIDGE_URL = bridgeUrl;
70
71 const gwEntry = pathToFileURL(path.join(projectRoot, 'hub', 'gateway', 'server.mjs')).href;
72 const { app: gwApp } = await import(`${gwEntry}?gwdelegation=${Date.now()}`);
73
74 const gwSrv = http.createServer(gwApp);
75 await new Promise((resolve, reject) => {
76 gwSrv.listen(0, '127.0.0.1', (err) => (err ? reject(err) : resolve()));
77 });
78 t.after(() => new Promise((r) => gwSrv.close(() => r())));
79
80 const port = gwSrv.address().port;
81 const token = signTestJwt({ sub: 'user-delegation-smoke', role: 'editor' });
82 const res = await fetch(`http://127.0.0.1:${port}/api/v1/delegation/grants`, {
83 method: 'POST',
84 headers: {
85 authorization: `Bearer ${token}`,
86 'content-type': 'application/json',
87 'x-vault-id': 'default',
88 },
89 body: JSON.stringify({ consent_id: 'dcons_test01', actor_agent_id: 'agent_tutor_test01' }),
90 });
91 assert.equal(res.status, 201);
92 const json = await res.json();
93 assert.equal(json.grant?.grant_id, 'dgrnt_test01');
94 assert.equal(calls.length, 1);
95 assert.equal(calls[0].method, 'POST');
96 assert.match(calls[0].auth, /^Bearer /);
97 assert.equal(calls[0].vault, 'default');
98 });
99
100 test('gateway source registers delegation proxy routes', () => {
101 const src = fs.readFileSync(path.join(projectRoot, 'hub', 'gateway', 'server.mjs'), 'utf8');
102 assert.match(src, /Agent delegation \(hosted parity — 7C-L1\)/);
103 assert.match(src, /\/api\/v1\/delegation\/grants/);
104 assert.match(src, /\/api\/v1\/agents\/identities/);
105 });
File History 2 commits
sha256:b5f647cb9c409f563d4671fe3fc05ddea01fabfed9b41fc11cb923588e1c1baf mirror: GitHub Phase A durable MCP OAuth (#270) Human minor 10 days ago
sha256:d8c648b20a4d53b2673c5c082ee7edfa7b2fc9b11080832da1f38807b6bf940b fix(7C-L1b): route hosted delegation proposals through cani… Human minor 30 days ago