diff --git a/internal/dev-entrypoint/cloud-web-routes.mjs b/internal/dev-entrypoint/cloud-web-routes.mjs index 8f057705..1428afcf 100644 --- a/internal/dev-entrypoint/cloud-web-routes.mjs +++ b/internal/dev-entrypoint/cloud-web-routes.mjs @@ -42,11 +42,20 @@ export function isCloudApiProxyRoute(method, pathname) { GET_PROXY_PREFIXES.some((prefix) => normalizedPath.startsWith(prefix)); } if (normalizedMethod === "POST") { - return POST_PROXY_ROUTES.has(normalizedPath); + return POST_PROXY_ROUTES.has(normalizedPath) || isDevicePodPostProxyRoute(normalizedPath); } return false; } +function isDevicePodPostProxyRoute(pathname) { + const parts = pathname.split("/").filter(Boolean); + if (parts.length < 4 || parts[0] !== "v1" || parts[1] !== "device-pods") return false; + if (parts.length === 4 && parts[3] === "jobs") return true; + if (parts.length === 4 && parts[3] === "leases") return true; + if (parts.length === 6 && parts[3] === "jobs" && parts[5] === "cancel") return true; + return false; +} + function isPublicCodeAgentPollRoute(method, pathname) { return method === "GET" && ( pathname.startsWith("/v1/agent/chat/result/") || diff --git a/internal/dev-entrypoint/cloud-web-routes.test.mjs b/internal/dev-entrypoint/cloud-web-routes.test.mjs index c7f395ff..f9c0224c 100644 --- a/internal/dev-entrypoint/cloud-web-routes.test.mjs +++ b/internal/dev-entrypoint/cloud-web-routes.test.mjs @@ -23,3 +23,36 @@ test("cloud web proxies skills routes through authenticated cloud-api", () => { routeKey: "POST /v1/skills/uploads" }); }); + +test("cloud web proxies only supported authenticated device-pod write routes", () => { + assert.deepEqual(cloudWebProxyRoutePolicy("POST", "/v1/device-pods/D601-F103-V2/jobs"), { + proxy: true, + authRequired: true, + publicRoute: false, + routeKey: "POST /v1/device-pods/D601-F103-V2/jobs" + }); + assert.deepEqual(cloudWebProxyRoutePolicy("POST", "/v1/device-pods/D601-F103-V2/jobs/job_1/cancel"), { + proxy: true, + authRequired: true, + publicRoute: false, + routeKey: "POST /v1/device-pods/D601-F103-V2/jobs/job_1/cancel" + }); + assert.deepEqual(cloudWebProxyRoutePolicy("POST", "/v1/device-pods/D601-F103-V2/leases"), { + proxy: true, + authRequired: true, + publicRoute: false, + routeKey: "POST /v1/device-pods/D601-F103-V2/leases" + }); + assert.deepEqual(cloudWebProxyRoutePolicy("POST", "/v1/device-pods/D601-F103-V2/status"), { + proxy: false, + authRequired: false, + publicRoute: false, + routeKey: "POST /v1/device-pods/D601-F103-V2/status" + }); + assert.deepEqual(cloudWebProxyRoutePolicy("POST", "/v1/device-pods/D601-F103-V2/jobs/job_1/output"), { + proxy: false, + authRequired: false, + publicRoute: false, + routeKey: "POST /v1/device-pods/D601-F103-V2/jobs/job_1/output" + }); +});