test: share gateway route auth helpers

This commit is contained in:
Peter Steinberger 2026-03-14 00:31:48 +00:00
parent 727fc79ed2
commit 4523260dda
2 changed files with 34 additions and 46 deletions

View File

@ -30,16 +30,20 @@ async function invokeSingleRunAbort({
}); });
} }
function createSingleAbortContext() {
return createChatAbortContext({
chatAbortControllers: new Map([
[
"run-1",
createActiveRun("main", { owner: { connId: "conn-owner", deviceId: "dev-owner" } }),
],
]),
});
}
describe("chat.abort authorization", () => { describe("chat.abort authorization", () => {
it("rejects explicit run aborts from other clients", async () => { it("rejects explicit run aborts from other clients", async () => {
const context = createChatAbortContext({ const context = createSingleAbortContext();
chatAbortControllers: new Map([
[
"run-1",
createActiveRun("main", { owner: { connId: "conn-owner", deviceId: "dev-owner" } }),
],
]),
});
const respond = await invokeSingleRunAbort({ const respond = await invokeSingleRunAbort({
context, context,
@ -104,14 +108,7 @@ describe("chat.abort authorization", () => {
}); });
it("allows operator.admin clients to bypass owner checks", async () => { it("allows operator.admin clients to bypass owner checks", async () => {
const context = createChatAbortContext({ const context = createSingleAbortContext();
chatAbortControllers: new Map([
[
"run-1",
createActiveRun("main", { owner: { connId: "conn-owner", deviceId: "dev-owner" } }),
],
]),
});
const respond = await invokeSingleRunAbort({ const respond = await invokeSingleRunAbort({
context, context,

View File

@ -111,6 +111,23 @@ function createSecurePluginRouteHandler(params: {
}); });
} }
async function invokeSecureGatewayRoute(params: { gatewayAuthSatisfied: boolean }) {
const exactPluginHandler = vi.fn(async () => false);
const prefixGatewayHandler = vi.fn(async () => true);
const handler = createSecurePluginRouteHandler({
exactPluginHandler,
prefixGatewayHandler,
});
const { res } = makeMockHttpResponse();
const handled = await handler(
{ url: "/plugin/secure/report" } as IncomingMessage,
res,
undefined,
{ gatewayAuthSatisfied: params.gatewayAuthSatisfied },
);
return { handled, exactPluginHandler, prefixGatewayHandler };
}
describe("createGatewayPluginRequestHandler", () => { describe("createGatewayPluginRequestHandler", () => {
it("caps unauthenticated plugin routes to non-admin subagent scopes", async () => { it("caps unauthenticated plugin routes to non-admin subagent scopes", async () => {
loadOpenClawPlugins.mockReset(); loadOpenClawPlugins.mockReset();
@ -232,44 +249,18 @@ describe("createGatewayPluginRequestHandler", () => {
}); });
it("fails closed when a matched gateway route reaches dispatch without auth", async () => { it("fails closed when a matched gateway route reaches dispatch without auth", async () => {
const exactPluginHandler = vi.fn(async () => false); const { handled, exactPluginHandler, prefixGatewayHandler } = await invokeSecureGatewayRoute({
const prefixGatewayHandler = vi.fn(async () => true); gatewayAuthSatisfied: false,
const handler = createSecurePluginRouteHandler({
exactPluginHandler,
prefixGatewayHandler,
}); });
const { res } = makeMockHttpResponse();
const handled = await handler(
{ url: "/plugin/secure/report" } as IncomingMessage,
res,
undefined,
{
gatewayAuthSatisfied: false,
},
);
expect(handled).toBe(false); expect(handled).toBe(false);
expect(exactPluginHandler).not.toHaveBeenCalled(); expect(exactPluginHandler).not.toHaveBeenCalled();
expect(prefixGatewayHandler).not.toHaveBeenCalled(); expect(prefixGatewayHandler).not.toHaveBeenCalled();
}); });
it("allows gateway route fallthrough only after gateway auth succeeds", async () => { it("allows gateway route fallthrough only after gateway auth succeeds", async () => {
const exactPluginHandler = vi.fn(async () => false); const { handled, exactPluginHandler, prefixGatewayHandler } = await invokeSecureGatewayRoute({
const prefixGatewayHandler = vi.fn(async () => true); gatewayAuthSatisfied: true,
const handler = createSecurePluginRouteHandler({
exactPluginHandler,
prefixGatewayHandler,
}); });
const { res } = makeMockHttpResponse();
const handled = await handler(
{ url: "/plugin/secure/report" } as IncomingMessage,
res,
undefined,
{
gatewayAuthSatisfied: true,
},
);
expect(handled).toBe(true); expect(handled).toBe(true);
expect(exactPluginHandler).toHaveBeenCalledTimes(1); expect(exactPluginHandler).toHaveBeenCalledTimes(1);
expect(prefixGatewayHandler).toHaveBeenCalledTimes(1); expect(prefixGatewayHandler).toHaveBeenCalledTimes(1);