Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline (Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/* packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
193 lines
6.6 KiB
TypeScript
193 lines
6.6 KiB
TypeScript
import http from "node:http";
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
import {
|
|
publishedLoopbackControlHostPort,
|
|
resolveComputerControlEndpoint,
|
|
} from "./computer-spec.js";
|
|
import { controlDesktop, MAX_COMPUTER_CONTROL_RESPONSE_BYTES } from "./index.js";
|
|
import {
|
|
attemptComputerControl,
|
|
preferComputerControl,
|
|
shouldReplayComputerActions,
|
|
} from "./supervisor-logic.js";
|
|
|
|
const token = "test-computer-control-token";
|
|
const actions = [{ kind: "key" as const, key: "Enter" }];
|
|
const observation = { image: "ZmFrZQ==", mimeType: "image/png", width: 1, height: 1 };
|
|
const servers: http.Server[] = [];
|
|
|
|
async function listen(handler: http.RequestListener) {
|
|
const server = http.createServer(handler);
|
|
servers.push(server);
|
|
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
const address = server.address();
|
|
if (!address || typeof address === "string") throw new Error("expected a TCP address");
|
|
return `http://127.0.0.1:${address.port}`;
|
|
}
|
|
|
|
afterEach(async () => {
|
|
await Promise.all(
|
|
servers.splice(0).map(
|
|
(server) =>
|
|
new Promise<void>((resolve, reject) => {
|
|
server.close((error) => (error ? reject(error) : resolve()));
|
|
server.closeAllConnections();
|
|
}),
|
|
),
|
|
);
|
|
});
|
|
|
|
describe("computer control HTTP boundary", () => {
|
|
it.each([false, true])("preserves direct desktop responses (observe=%s)", async (observe) => {
|
|
const requests: Array<{ url?: string; method?: string; authorization?: string; body: string }> =
|
|
[];
|
|
const result = { completed: 1, ...(observe ? { observation } : {}) };
|
|
const origin = await listen(async (req, res) => {
|
|
const chunks: Buffer[] = [];
|
|
for await (const chunk of req) chunks.push(Buffer.from(chunk));
|
|
requests.push({
|
|
url: req.url,
|
|
method: req.method,
|
|
authorization: req.headers.authorization,
|
|
body: Buffer.concat(chunks).toString(),
|
|
});
|
|
res.setHeader("content-type", "application/json");
|
|
res.end(JSON.stringify(result));
|
|
});
|
|
|
|
await expect(
|
|
controlDesktop(
|
|
{ url: `${origin}/v1/desktop`, token },
|
|
actions,
|
|
":2",
|
|
"/tmp/test-profile",
|
|
observe,
|
|
25,
|
|
),
|
|
).resolves.toEqual(result);
|
|
expect(requests).toEqual([
|
|
{
|
|
url: "/v1/desktop",
|
|
method: "POST",
|
|
authorization: `Bearer ${token}`,
|
|
body: JSON.stringify({
|
|
steps: [{ argv: ["env", "DISPLAY=:2", "xdotool", "key", "--clearmodifiers", "Return"] }],
|
|
display: ":2",
|
|
observe,
|
|
settleMs: 25,
|
|
}),
|
|
},
|
|
]);
|
|
});
|
|
|
|
it("sends token-authenticated actions to the inspected host mapping without a container IP", async () => {
|
|
const authorizations: Array<string | undefined> = [];
|
|
const origin = await listen((req, res) => {
|
|
req.resume();
|
|
authorizations.push(req.headers.authorization);
|
|
if (req.headers.authorization !== `Bearer ${token}`) {
|
|
res.writeHead(401).end();
|
|
return;
|
|
}
|
|
res.setHeader("content-type", "application/json");
|
|
res.end(JSON.stringify({ completed: 1 }));
|
|
});
|
|
const publishedHostPort = publishedLoopbackControlHostPort({
|
|
"7070/tcp": [{ HostIp: "127.0.0.1", HostPort: new URL(origin).port }],
|
|
});
|
|
const endpoint = resolveComputerControlEndpoint({
|
|
token,
|
|
networkMode: "bridge",
|
|
networks: {},
|
|
publishedHostPort,
|
|
requirePublishedHostPort: true,
|
|
});
|
|
expect(endpoint).toEqual({ url: `${origin}/v1/desktop`, token });
|
|
if (!endpoint) throw new Error("expected a loopback endpoint");
|
|
await expect(
|
|
controlDesktop(endpoint, actions, ":1", "/tmp/test-profile", false, 0),
|
|
).resolves.toEqual({
|
|
completed: 1,
|
|
});
|
|
await expect(
|
|
controlDesktop(
|
|
{ ...endpoint, token: "wrong-token" },
|
|
actions,
|
|
":1",
|
|
"/tmp/test-profile",
|
|
false,
|
|
0,
|
|
),
|
|
).rejects.toThrow();
|
|
expect(authorizations).toEqual([`Bearer ${token}`, "Bearer wrong-token"]);
|
|
});
|
|
|
|
it("rejects an oversized computer-control response before reading it", async () => {
|
|
const origin = await listen((req, res) => {
|
|
req.resume();
|
|
res.writeHead(200, {
|
|
"content-type": "application/json",
|
|
"content-length": String(MAX_COMPUTER_CONTROL_RESPONSE_BYTES + 1),
|
|
});
|
|
res.end("{}");
|
|
});
|
|
|
|
await expect(
|
|
controlDesktop(
|
|
{ url: `${origin}/v1/desktop`, token },
|
|
actions,
|
|
":1",
|
|
"/tmp/test-profile",
|
|
false,
|
|
0,
|
|
),
|
|
).rejects.toThrow(`exceeds ${MAX_COMPUTER_CONTROL_RESPONSE_BYTES} bytes`);
|
|
});
|
|
|
|
describe.each([301, 302, 303, 307, 308])("HTTP %s", (status) => {
|
|
it.each(["same origin", "other origin"])(
|
|
"never contacts a redirect target on the %s or replays actions",
|
|
async (destination) => {
|
|
const targetRequests: Array<{ method?: string; authorization?: string }> = [];
|
|
const target: http.RequestListener = (req, res) => {
|
|
targetRequests.push({ method: req.method, authorization: req.headers.authorization });
|
|
// Even a response matching the control contract must never be accepted
|
|
// from another endpoint. These servers are loopback-only fake services.
|
|
res.setHeader("content-type", "application/json");
|
|
res.end(JSON.stringify({ completed: 1, observation }));
|
|
};
|
|
const location =
|
|
destination === "same origin" ? "/other-endpoint" : `${await listen(target)}/v1/desktop`;
|
|
let controlRequests = 0;
|
|
const origin = await listen((req, res) => {
|
|
if (req.url !== "/v1/desktop") return target(req, res);
|
|
controlRequests += 1;
|
|
req.resume();
|
|
res.writeHead(status, { location });
|
|
res.end();
|
|
});
|
|
const endpoint = { url: `${origin}/v1/desktop`, token };
|
|
|
|
const attempt = await attemptComputerControl(() =>
|
|
controlDesktop(endpoint, actions, ":1", "/tmp/test-profile", false, 0),
|
|
);
|
|
expect(targetRequests).toEqual([]);
|
|
expect(attempt.status).toBe("failed");
|
|
expect(shouldReplayComputerActions(attempt)).toBe(false);
|
|
|
|
// Observation may fall back to Docker exec on the original computer.
|
|
const fallbackObservation = { source: "original-computer" };
|
|
await expect(
|
|
preferComputerControl(
|
|
async () =>
|
|
(await controlDesktop(endpoint, [], ":1", "/tmp/test-profile", true, 0)).observation,
|
|
async () => fallbackObservation,
|
|
),
|
|
).resolves.toEqual(fallbackObservation);
|
|
expect(targetRequests).toEqual([]);
|
|
expect(controlRequests).toBe(2);
|
|
},
|
|
);
|
|
});
|
|
});
|