Files
cobble/src/utils/computer-proxy-headers.test.ts
T
tbenandClaude Opus 5.5 56daf0c462 Open computers from the chat, let bots ask for a take-over, show task progress
- Serve each computer to its owner under /computers/<id>/ (HTTP and
  websockets proxied to the AIO sandbox) and show it in a shared
  ComputerView with browser, terminal and code modes, opened from the
  computers modal or a take-over button in the thread.
- ask_user_to_take_over lets a bot hand a computer to the user for a
  login or captcha; the message gets a take-over button and needs-you,
  and the viewer hands it back with a chat message.
- While a task runs the thread shows "<bot> is working..." with the
  task's latest step; steps read as plain words, not tool names.
- A coordinator with no workers no longer claims to delegate, and bots
  describe started tasks in the first person.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 05:35:44 +01:00

69 lines
2.9 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import { AppData } from "@/src/data/app-data";
import computerProxyRequestHeaders from "./computer-proxy-request-headers";
import computerProxyResponseHeaders from "./computer-proxy-response-headers";
describe("computerProxyRequestHeaders", () => {
test("drops the app's session cookies and forwards where it's served", () => {
const headers = computerProxyRequestHeaders({
headers: new Headers({
host: "localhost:7227",
cookie: `${AppData.AuthKeyCookieName}=secret; ${AppData.AuthCSRFCookieName}=csrf; _xsrf=keep`,
"user-agent": "test",
}),
url: new URL("http://localhost:7227/computers/3/terminal"),
prefix: "/computers/3",
});
expect(headers.get("cookie")).toBe("_xsrf=keep");
expect(headers.get("host")).toBeNull();
expect(headers.get("user-agent")).toBe("test");
expect(headers.get("x-forwarded-host")).toBe("localhost:7227");
expect(headers.get("x-forwarded-proto")).toBe("http");
expect(headers.get("x-forwarded-prefix")).toBe("/computers/3");
});
test("sends no cookie header when only the app's were set", () => {
const headers = computerProxyRequestHeaders({
headers: new Headers({ cookie: `${AppData.AuthKeyCookieName}=secret` }),
url: new URL("https://cobble.local/computers/3/"),
prefix: "/computers/3",
});
expect(headers.get("cookie")).toBeNull();
expect(headers.get("x-forwarded-proto")).toBe("https");
});
});
describe("computerProxyResponseHeaders", () => {
const base_url = "http://cobble-computer:8080";
const prefix = "/computers/3";
test("lets the chat frame the computer", () => {
const headers = computerProxyResponseHeaders({
headers: new Headers({
"x-frame-options": "DENY",
"content-security-policy": "default-src 'self'; frame-ancestors 'none'",
}),
base_url,
prefix,
});
expect(headers.get("x-frame-options")).toBeNull();
expect(headers.get("content-security-policy")).toBe("default-src 'self'");
});
test("points redirects back under the prefix", () => {
const location = (value: string) =>
computerProxyResponseHeaders({ headers: new Headers({ location: value }), base_url, prefix }).get(
"location",
);
expect(location("http://cobble-computer:8080/jupyter/lab")).toBe("/computers/3/jupyter/lab");
expect(location("/code-server?folder=/home/gem")).toBe("/computers/3/code-server?folder=/home/gem");
expect(location("/computers/3/terminal")).toBe("/computers/3/terminal");
expect(location("./?folder=/home/gem")).toBe("./?folder=/home/gem");
expect(location("https://example.com/")).toBe("https://example.com/");
});
});