OpenCode tools run in a child service, so they cannot read the Agent process-local session map. Hydrate a sanitized context through the authenticated internal bridge and centralize backend project headers to prevent context loss across both boundaries.
84 lines
2.6 KiB
TypeScript
84 lines
2.6 KiB
TypeScript
import { afterEach, describe, expect, it } from "bun:test";
|
|
|
|
import {
|
|
readBridgedRuntimeSessionContext,
|
|
serializeRuntimeSessionContext,
|
|
} from "../../src/runtime/internalSessionContextBridge.js";
|
|
import { removeRuntimeSessionContext } from "../../src/runtime/sessionContext.js";
|
|
|
|
describe("readBridgedRuntimeSessionContext", () => {
|
|
const sessionId = "remote-opencode-session";
|
|
|
|
afterEach(() => {
|
|
removeRuntimeSessionContext(sessionId);
|
|
});
|
|
|
|
it("hydrates a child-process context through the authenticated internal bridge", async () => {
|
|
const calls: Array<{ input: string; init?: RequestInit }> = [];
|
|
const context = await readBridgedRuntimeSessionContext(sessionId, {
|
|
baseUrl: "http://127.0.0.1:8787",
|
|
internalToken: "internal-secret",
|
|
fetchImpl: async (input, init) => {
|
|
calls.push({ input: String(input), init });
|
|
return Response.json({
|
|
actor_key: "actor-1",
|
|
allow_learning_write: true,
|
|
client_session_id: "client-session-1",
|
|
project_key: "project-1",
|
|
session_id: sessionId,
|
|
trace_id: "trace-1",
|
|
});
|
|
},
|
|
});
|
|
|
|
expect(context).toMatchObject({
|
|
actorKey: "actor-1",
|
|
allowLearningWrite: true,
|
|
clientSessionId: "client-session-1",
|
|
projectKey: "project-1",
|
|
sessionId,
|
|
traceId: "trace-1",
|
|
});
|
|
expect(calls).toHaveLength(1);
|
|
expect(calls[0]?.input).toBe(
|
|
"http://127.0.0.1:8787/internal/tools/session-context",
|
|
);
|
|
expect(calls[0]?.init?.headers).toEqual({
|
|
"Content-Type": "application/json",
|
|
"x-agent-internal-token": "internal-secret",
|
|
});
|
|
expect(JSON.parse(String(calls[0]?.init?.body))).toEqual({
|
|
session_id: sessionId,
|
|
});
|
|
});
|
|
|
|
it("does not expose backend credentials to the opencode child process", () => {
|
|
const context = {
|
|
accessToken: "backend-secret",
|
|
actorKey: "actor-1",
|
|
clientSessionId: "client-session-1",
|
|
network: "network-1",
|
|
projectId: "project-id-1",
|
|
projectKey: "project-key-1",
|
|
sessionId,
|
|
traceId: "trace-1",
|
|
};
|
|
expect(context).toHaveProperty("accessToken", "backend-secret");
|
|
|
|
const payload = serializeRuntimeSessionContext(context);
|
|
|
|
expect(payload).toEqual({
|
|
actor_key: "actor-1",
|
|
allow_learning_write: undefined,
|
|
client_session_id: "client-session-1",
|
|
memory_list_read_scopes: undefined,
|
|
project_key: "project-key-1",
|
|
session_id: sessionId,
|
|
trace_id: "trace-1",
|
|
});
|
|
expect(payload).not.toHaveProperty("access_token");
|
|
expect(payload).not.toHaveProperty("project_id");
|
|
expect(payload).not.toHaveProperty("network");
|
|
});
|
|
});
|