mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-26 16:06:16 +00:00
fix(gateway): bind OpenResponses HTTP ingress as non-owner (#57778)
* fix(gateway): bind OpenResponses HTTP ingress as non-owner Co-authored-by: bmendonca3 <208517100+bmendonca3@users.noreply.github.com> * test(gateway): cover streaming OpenResponses non-owner ingress --------- Co-authored-by: bmendonca3 <208517100+bmendonca3@users.noreply.github.com>
This commit is contained in:
@@ -700,6 +700,62 @@ describe("OpenResponses HTTP API (e2e)", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("treats HTTP callers as non-owner regardless of requested scopes", async () => {
|
||||||
|
const port = enabledPort;
|
||||||
|
|
||||||
|
agentCommand.mockClear();
|
||||||
|
agentCommand.mockResolvedValueOnce({ payloads: [{ text: "hello" }] } as never);
|
||||||
|
|
||||||
|
const writeScopeResponse = await postResponses(port, {
|
||||||
|
model: "openclaw",
|
||||||
|
input: "hi",
|
||||||
|
});
|
||||||
|
expect(writeScopeResponse.status).toBe(200);
|
||||||
|
const writeScopeOpts = (agentCommand.mock.calls[0] as unknown[] | undefined)?.[0] as
|
||||||
|
| { senderIsOwner?: boolean }
|
||||||
|
| undefined;
|
||||||
|
expect(writeScopeOpts?.senderIsOwner).toBe(false);
|
||||||
|
await ensureResponseConsumed(writeScopeResponse);
|
||||||
|
|
||||||
|
agentCommand.mockClear();
|
||||||
|
agentCommand.mockResolvedValueOnce({ payloads: [{ text: "hello" }] } as never);
|
||||||
|
|
||||||
|
const adminScopeResponse = await postResponses(
|
||||||
|
port,
|
||||||
|
{ model: "openclaw", input: "hi" },
|
||||||
|
{ "x-openclaw-scopes": "operator.admin, operator.write" },
|
||||||
|
);
|
||||||
|
expect(adminScopeResponse.status).toBe(200);
|
||||||
|
const adminScopeOpts = (agentCommand.mock.calls[0] as unknown[] | undefined)?.[0] as
|
||||||
|
| { senderIsOwner?: boolean }
|
||||||
|
| undefined;
|
||||||
|
// Requested HTTP scopes do not prove owner identity for owner-only tools.
|
||||||
|
expect(adminScopeOpts?.senderIsOwner).toBe(false);
|
||||||
|
await ensureResponseConsumed(adminScopeResponse);
|
||||||
|
|
||||||
|
agentCommand.mockClear();
|
||||||
|
agentCommand.mockImplementationOnce((async (opts: unknown) =>
|
||||||
|
buildAssistantDeltaResult({
|
||||||
|
opts,
|
||||||
|
emit: emitAgentEvent,
|
||||||
|
deltas: ["he", "llo"],
|
||||||
|
text: "hello",
|
||||||
|
})) as never);
|
||||||
|
|
||||||
|
const streamingResponse = await postResponses(
|
||||||
|
port,
|
||||||
|
{ stream: true, model: "openclaw", input: "hi" },
|
||||||
|
{ "x-openclaw-scopes": "operator.admin, operator.write" },
|
||||||
|
);
|
||||||
|
expect(streamingResponse.status).toBe(200);
|
||||||
|
const streamingOpts = (agentCommand.mock.calls[0] as unknown[] | undefined)?.[0] as
|
||||||
|
| { senderIsOwner?: boolean }
|
||||||
|
| undefined;
|
||||||
|
expect(streamingOpts?.senderIsOwner).toBe(false);
|
||||||
|
const streamingEvents = parseSseEvents(await streamingResponse.text());
|
||||||
|
expect(streamingEvents.some((event) => event.event === "response.completed")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
it("preserves assistant text alongside non-stream function_call output", async () => {
|
it("preserves assistant text alongside non-stream function_call output", async () => {
|
||||||
const port = enabledPort;
|
const port = enabledPort;
|
||||||
agentCommand.mockClear();
|
agentCommand.mockClear();
|
||||||
|
|||||||
@@ -424,6 +424,7 @@ async function runResponsesAgentCommand(params: {
|
|||||||
sessionKey: string;
|
sessionKey: string;
|
||||||
runId: string;
|
runId: string;
|
||||||
messageChannel: string;
|
messageChannel: string;
|
||||||
|
senderIsOwner: boolean;
|
||||||
deps: ReturnType<typeof createDefaultDeps>;
|
deps: ReturnType<typeof createDefaultDeps>;
|
||||||
}) {
|
}) {
|
||||||
return agentCommandFromIngress(
|
return agentCommandFromIngress(
|
||||||
@@ -439,8 +440,7 @@ async function runResponsesAgentCommand(params: {
|
|||||||
deliver: false,
|
deliver: false,
|
||||||
messageChannel: params.messageChannel,
|
messageChannel: params.messageChannel,
|
||||||
bestEffortDeliver: false,
|
bestEffortDeliver: false,
|
||||||
// HTTP API callers are authenticated operator clients for this gateway context.
|
senderIsOwner: params.senderIsOwner,
|
||||||
senderIsOwner: true,
|
|
||||||
allowModelOverride: true,
|
allowModelOverride: true,
|
||||||
},
|
},
|
||||||
defaultRuntime,
|
defaultRuntime,
|
||||||
@@ -704,6 +704,7 @@ export async function handleOpenResponsesHttpRequest(
|
|||||||
sessionKey,
|
sessionKey,
|
||||||
runId: responseId,
|
runId: responseId,
|
||||||
messageChannel,
|
messageChannel,
|
||||||
|
senderIsOwner: false,
|
||||||
deps,
|
deps,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -956,6 +957,7 @@ export async function handleOpenResponsesHttpRequest(
|
|||||||
sessionKey,
|
sessionKey,
|
||||||
runId: responseId,
|
runId: responseId,
|
||||||
messageChannel,
|
messageChannel,
|
||||||
|
senderIsOwner: false,
|
||||||
deps,
|
deps,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user