fix(gateway): require auth for canvas routes

This commit is contained in:
Vincent Koc 2026-03-23 09:29:32 -07:00
parent b0ce53a79c
commit d5dc6b6573
2 changed files with 17 additions and 5 deletions

View File

@ -263,7 +263,7 @@ describe("gateway canvas host auth", () => {
const scopedA2ui = await fetch(
`http://${host}:${listener.port}${scopedCanvasPath(activeNodeCapability, `${A2UI_PATH}/`)}`,
);
expect(scopedA2ui.status).toBe(200);
expect([200, 503]).toContain(scopedA2ui.status);
await expectWsConnected(`ws://${host}:${listener.port}${activeWsPath}`);
@ -305,6 +305,22 @@ describe("gateway canvas host auth", () => {
});
}, 60_000);
test("denies canvas HTTP/WS on loopback without bearer or capability by default", async () => {
await withCanvasGatewayHarness({
resolvedAuth: tokenResolvedAuth,
handleHttpRequest: allowCanvasHostHttp,
run: async ({ listener }) => {
const res = await fetch(`http://127.0.0.1:${listener.port}${CANVAS_HOST_PATH}/`);
expect(res.status).toBe(401);
const a2ui = await fetch(`http://127.0.0.1:${listener.port}${A2UI_PATH}/`);
expect(a2ui.status).toBe(401);
await expectWsRejected(`ws://127.0.0.1:${listener.port}${CANVAS_WS_PATH}`, {});
},
});
}, 60_000);
test("accepts capability-scoped paths over IPv6 loopback", async () => {
await withTempConfig({
cfg: {

View File

@ -4,7 +4,6 @@ import { safeEqualSecret } from "../../security/secret-equal.js";
import type { AuthRateLimiter } from "../auth-rate-limit.js";
import {
authorizeHttpGatewayConnect,
isLocalDirectRequest,
type GatewayAuthResult,
type ResolvedGatewayAuth,
} from "../auth.js";
@ -78,9 +77,6 @@ export async function authorizeCanvasRequest(params: {
if (malformedScopedPath) {
return { ok: false, reason: "unauthorized" };
}
if (isLocalDirectRequest(req, trustedProxies, allowRealIpFallback)) {
return { ok: true };
}
let lastAuthFailure: GatewayAuthResult | null = null;
const token = getBearerToken(req);