Skip to content

Commit b3e8966

Browse files
fix(proxy): rewrite agent_id in URL path segments for /v1/agents/{id}/... (DAK-6901)
fix(proxy): rewrite agent_id in URL path segments for /v1/agents/{id}/... (DAK-6901)
2 parents 5dc17b4 + ad8ddd2 commit b3e8966

2 files changed

Lines changed: 49 additions & 7 deletions

File tree

docker/playground/proxy/proxy.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,3 +794,27 @@ test('llm-compare endpoint accessible via HTTP proxy (integration, DAK-6845)', a
794794
assert.ok(json.without_memory !== undefined || json.error, 'response must be structured');
795795
await p.close();
796796
});
797+
798+
test('agent_id in URL path segment is namespaced for /v1/agents/{id}/memories (DAK-6901)', async () => {
799+
const p = await startProxy({ rateLimitPerMin: 1000 });
800+
// GET /v1/agents/playground-demo/memories — agent_id is in the URL path, not body/query
801+
const res = await request(p.port, {
802+
method: 'GET',
803+
path: '/v1/agents/playground-demo/memories',
804+
headers: { 'x-playground-session': 'pg_pathtest001' },
805+
});
806+
// Must reach the upstream (not 403 forbidden_endpoint)
807+
assert.notEqual(res.status, 403, 'GET /v1/agents/{id}/memories must pass the allow-list');
808+
// The forwarded URL path must have the session-namespaced agent_id, not the raw client value
809+
const forwarded = p.upstream.captured[0];
810+
assert.ok(forwarded, 'request must be forwarded to upstream');
811+
assert.ok(
812+
forwarded.url.includes('/v1/agents/playground-demo-'),
813+
`agent_id in path must be namespaced, got: ${forwarded.url}`,
814+
);
815+
assert.ok(
816+
!forwarded.url.includes('/v1/agents/playground-demo/'),
817+
`raw client agent_id must not reach engine, got: ${forwarded.url}`,
818+
);
819+
await p.close();
820+
});

docker/playground/proxy/server.js

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -416,16 +416,34 @@ function createServer(config, store) {
416416
};
417417
}
418418

419-
// Also rewrite agent_id in URL query params for GET endpoints (DAK-6899)
419+
// Rewrite agent_id in URL path segments (/v1/agents/{id}/...) and query params.
420+
// Body rewriting is handled above; path segments and query params need explicit
421+
// treatment because rewriteRequestAgentId only touches JSON body fields (DAK-6901).
420422
let forwardPath = path;
421423
try {
422-
const qUrl = new URL(req.url, "http://localhost");
423-
if (qUrl.searchParams.has("agent_id")) {
424-
const namespace = sessionNamespace(resolved.id);
425-
const qAgentId = qUrl.searchParams.get("agent_id");
426-
qUrl.searchParams.set("agent_id", namespace);
427-
forwardPath = qUrl.pathname + "?" + qUrl.searchParams.toString();
424+
const fUrl = new URL(req.url, "http://localhost");
425+
const namespace = sessionNamespace(resolved.id);
426+
let modified = false;
427+
428+
// Path-segment rewrite: /v1/agents/{agent_id}/... (DAK-6901)
429+
const segMatch = fUrl.pathname.match(/^(\/v1\/agents\/)([^/]+)(\/.*)?$/);
430+
if (segMatch) {
431+
const clientId = segMatch[2];
432+
fUrl.pathname = segMatch[1] + namespace + (segMatch[3] || '');
433+
if (!rewrite) rewrite = { namespace, restoreTo: clientId };
434+
modified = true;
435+
}
436+
437+
// Query-param rewrite: ?agent_id=... (DAK-6899)
438+
if (fUrl.searchParams.has("agent_id")) {
439+
const qAgentId = fUrl.searchParams.get("agent_id");
440+
fUrl.searchParams.set("agent_id", namespace);
428441
if (!rewrite) rewrite = { namespace, restoreTo: qAgentId };
442+
modified = true;
443+
}
444+
445+
if (modified) {
446+
forwardPath = fUrl.pathname + (fUrl.search || '');
429447
}
430448
} catch (_) {}
431449
forward(config, req, res, forwardPath, bodyBuf, outHeaders, rewrite);

0 commit comments

Comments
 (0)