源码快照 @ 2026-09-02 (source-only, 剔除非源码素材)

This commit is contained in:
agent-radar
2026-09-02 01:05:41 +08:00
commit 04bac1f6e2
2200 changed files with 489415 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
{
"name": "@openwork/testkit",
"version": "0.0.0",
"private": true,
"type": "module",
"exports": {
".": {
"types": "./src/index.ts",
"development": "./src/index.ts",
"default": "./src/index.ts"
},
"./stack": "./src/stack.ts"
},
"dependencies": {
"@openwork/behaviors": "workspace:*",
"@openwork/cdp": "workspace:*",
"@openwork/env": "workspace:*",
"@openwork/test-evidence": "workspace:*",
"@openwork/hosts": "workspace:*",
"@openwork/labs": "workspace:*",
"mysql2": "^3.11.3",
"vitest": "^3.2.4"
}
}
@@ -0,0 +1,20 @@
import { resolvePlace } from "@openwork/env";
export interface TestContext {
place: ReturnType<typeof resolvePlace>;
evidence: unknown;
skip(note?: string): never;
}
export type RegisterTest = (title: string, fn: (ctx: TestContext) => Promise<void> | void) => void;
let registerTest: RegisterTest | undefined;
export function setBriefTestRegistrar(registrar: RegisterTest): void {
registerTest = registrar;
}
export function getBriefTestRegistrar(): RegisterTest {
if (!registerTest) throw new Error("briefTest must be imported from @openwork/testkit.");
return registerTest;
}
+97
View File
@@ -0,0 +1,97 @@
import { currentTestEvidence } from "@openwork/test-evidence";
import { getBriefTestRegistrar } from "./brief-internal.ts";
import type { TestContext } from "./brief-internal.ts";
export interface BriefClaim {
must: string;
never?: string;
}
export function claim(must: string, opts: { never?: string } = {}): BriefClaim {
return { must, ...opts };
}
export interface TestBrief<K extends string> {
behavior: string;
claims: Record<K, BriefClaim>;
}
export function testBrief<K extends string>(def: TestBrief<K>): TestBrief<K> {
if (!def.behavior.trim()) throw new Error("Test brief behavior must not be empty.");
const keys = Object.keys(def.claims);
if (keys.length === 0) throw new Error("Test brief must declare at least one claim.");
for (const key in def.claims) {
const value = def.claims[key];
if (!value.must.trim()) throw new Error(`Test brief claim "${key}" must not have a blank must.`);
if (value.never !== undefined && !value.never.trim()) {
throw new Error(`Test brief claim "${key}" must not have a blank never.`);
}
}
return def;
}
export type Prove<K extends string> = Record<K, (passed: boolean, evidence: string) => void>;
export interface BriefRun<K extends string> {
prove: Prove<K>;
assertAllProven(): void;
facts(): { key: K; passed: boolean; evidence: string }[];
}
export function createBriefRun<K extends string>(
brief: TestBrief<K>,
record: (claimText: string, evidence: string, passed: boolean) => void = (claimText, evidence, passed) => {
currentTestEvidence()?.recordAssertionEvidence(claimText, evidence, passed);
},
): BriefRun<K> {
const latest = new Map<K, { key: K; passed: boolean; evidence: string }>();
const prove: Prove<K> = Object.create(null);
for (const key in brief.claims) {
const value = brief.claims[key];
prove[key] = (passed, evidence) => {
if (!evidence.trim()) throw new Error(`Proof evidence for claim "${key}" must not be blank.`);
const claimText = `${key}: ${value.must}${value.never === undefined ? "" : ` — never: ${value.never}`}`;
record(claimText, evidence, passed);
latest.set(key, { key, passed, evidence });
if (passed !== true) throw new Error(`Claim failed: ${key} — ${value.must}. Evidence: ${evidence}`);
};
}
return {
prove,
assertAllProven() {
const missing: K[] = [];
for (const key in brief.claims) {
if (!latest.has(key)) missing.push(key);
}
if (missing.length > 0) {
throw new Error(`Brief claims left unproven: ${missing.join(", ")}. Every declared claim needs a prove.<claim>() call.`);
}
},
facts: () => [...latest.values()],
};
}
interface BriefTestContext<K extends string> {
prove: Prove<K>;
place: TestContext["place"];
evidence: TestContext["evidence"];
skip: TestContext["skip"];
}
function briefTitle(behavior: string): string {
const sentence = behavior.split(".", 1)[0].trim();
return sentence.length <= 100 ? sentence : `${sentence.slice(0, 97)}...`;
}
export function briefTest<K extends string>(
brief: TestBrief<K>,
fn: (ctx: BriefTestContext<K>) => Promise<void> | void,
): void {
getBriefTestRegistrar()(briefTitle(brief.behavior), async ({ place, evidence, skip }) => {
const run = createBriefRun(brief);
await fn({ prove: run.prove, place, evidence, skip });
run.assertAllProven();
});
}
+51
View File
@@ -0,0 +1,51 @@
export interface EventuallyOptions<T> {
within: number;
intervalMs?: number;
label?: string;
until?: (value: T) => boolean;
}
export function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
function describe(value: unknown): string {
try {
const json = JSON.stringify(value);
return json === undefined ? String(value) : json;
} catch {
return String(value);
}
}
export async function eventually<T>(
probe: () => Promise<T> | T,
options: EventuallyOptions<T>,
): Promise<T> {
const intervalMs = options.intervalMs ?? 500;
const until = options.until ?? ((value: T) => Boolean(value));
const deadline = Date.now() + options.within;
let lastValue: T | undefined;
let lastError: unknown;
let hasValue = false;
while (true) {
try {
lastValue = await probe();
hasValue = true;
lastError = undefined;
if (until(lastValue)) return lastValue;
} catch (error) {
lastError = error;
}
const remaining = deadline - Date.now();
if (remaining <= 0) {
const label = options.label ?? "condition";
const valueDetail = hasValue ? `; last value: ${describe(lastValue)}` : "";
const errorDetail = lastError === undefined ? "" : `; last error: ${describe(lastError instanceof Error ? lastError.message : lastError)}`;
throw new Error(`Timed out waiting for ${label} after ${options.within}ms${valueDetail}${errorDetail}`);
}
await sleep(Math.min(intervalMs, remaining));
}
}
+51
View File
@@ -0,0 +1,51 @@
import { test as evidenceTest } from "@openwork/test-evidence/vitest";
import { SkipError, resolvePlace } from "@openwork/env";
import { setBriefTestRegistrar } from "./brief-internal.ts";
const fixtureTest = evidenceTest.extend<{ place: ReturnType<typeof resolvePlace> }>({
place: [async ({}, use) => {
await use(resolvePlace(process.env));
}, { auto: true }],
});
interface WrappedContext {
place: ReturnType<typeof resolvePlace>;
evidence: unknown;
skip(note?: string): never;
}
// Vitest does not propagate a test-body error back through fixture `use()`, so
// the exported test boundary is where SkipError can reliably become ctx.skip().
function wrapTestApi<T extends (...args: never[]) => unknown>(api: T): T {
return new Proxy(api, {
apply(target, thisArg, argArray) {
const args = [...argArray];
const callback = args.at(-1);
if (typeof callback === "function") {
args[args.length - 1] = async ({ place, evidence, skip }: WrappedContext) => {
try {
return await Reflect.apply(callback, undefined, [{ place, evidence, skip }]);
} catch (error) {
if (!(error instanceof SkipError)) throw error;
return skip(`needs: ${error.reason}`);
}
};
}
return Reflect.apply(target, thisArg, args);
},
get(target, property, receiver) {
const value = Reflect.get(target, property, receiver);
if (typeof value !== "function") return value;
return (...args: unknown[]) => {
const result = Reflect.apply(value, target, args);
return typeof result === "function" ? wrapTestApi(result) : result;
};
},
});
}
export const test = wrapTestApi(fixtureTest);
setBriefTestRegistrar((title, fn) => {
test(title, fn);
});
+9
View File
@@ -0,0 +1,9 @@
export { createDesktopHandoffGrant, signInDesktopAs } from "@openwork/behaviors";
export type { DesktopHandle } from "@openwork/hosts";
export { test } from "./fixture.ts";
export * from "@openwork/env";
export * from "./brief.ts";
export * from "./eventually.ts";
export * from "./link.ts";
export * from "./self-host.ts";
export * from "./state.ts";
+414
View File
@@ -0,0 +1,414 @@
import { createServer, request as httpRequest } from "node:http";
import { request as httpsRequest } from "node:https";
import { createHash, timingSafeEqual } from "node:crypto";
import { clearTimeout, setTimeout } from "node:timers";
import { URL } from "node:url";
const HOP_BY_HOP_HEADERS = new Set([
"connection",
"keep-alive",
"proxy-authenticate",
"proxy-authorization",
"proxy-connection",
"te",
"trailer",
"transfer-encoding",
"upgrade",
]);
function cliValue(name, fallback) {
const index = process.argv.indexOf(`--${name}`);
return index >= 0 ? process.argv[index + 1] : fallback;
}
function requiredPort(value, name) {
const port = Number(value);
if (!Number.isInteger(port) || port < 1 || port > 65_535) throw new Error(`${name} must be a valid port.`);
return port;
}
const upstream = new URL(cliValue("upstream", process.env.LINK_UPSTREAM));
const dataPort = requiredPort(cliValue("port", process.env.LINK_PORT), "port");
const adminPort = requiredPort(cliValue("admin-port", process.env.LINK_ADMIN_PORT), "admin-port");
const adminToken = process.env.LINK_ADMIN_TOKEN ?? cliValue("admin-token");
if (upstream.protocol !== "http:" && upstream.protocol !== "https:") throw new Error("upstream must use http or https.");
if (typeof adminToken !== "string" || !/^[a-f0-9]{32,}$/.test(adminToken)) throw new Error("admin token must be at least 32 hex characters.");
const expectedAuthorizationHash = createHash("sha256").update(`Bearer ${adminToken}`).digest();
let phase = "default";
let profile = "baseline";
let rules = [];
let bytesPerSec = null;
let offline = false;
let offlineUntil = null;
let offlineTimer = null;
let shuttingDown = false;
const requests = [];
const refusedConnections = Object.create(null);
const dataSockets = new Set();
const adminSockets = new Set();
const stalledSockets = new Set();
function sleep(milliseconds) {
return new Promise((resolve) => setTimeout(resolve, milliseconds));
}
function isRecord(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function headerText(value) {
return Array.isArray(value) ? value.join(",") : value ?? "";
}
function forwardedHeaders(source, host) {
const nominated = new Set(headerText(source.connection).split(",").map((name) => name.trim().toLowerCase()).filter(Boolean));
const headers = {};
for (const [name, value] of Object.entries(source)) {
if (value === undefined || HOP_BY_HOP_HEADERS.has(name) || nominated.has(name)) continue;
headers[name] = value;
}
if (host) headers.host = host;
return headers;
}
function nonNegativeNumber(value, name) {
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) throw new Error(`${name} must be a non-negative number.`);
return value;
}
function positiveInteger(value, name) {
if (!Number.isInteger(value) || value < 1) throw new Error(`${name} must be a positive integer.`);
return value;
}
function normalizeRule(value) {
if (!isRecord(value) || typeof value.kind !== "string") throw new Error("Each rule must be an object with a kind.");
const pathPrefix = value.pathPrefix === undefined ? "/" : value.pathPrefix;
if (typeof pathPrefix !== "string") throw new Error("Rule pathPrefix must be a string.");
const everyNth = value.everyNth === undefined ? null : positiveInteger(value.everyNth, "Rule everyNth");
let remaining = everyNth === null ? 1 : Infinity;
if (value.times !== undefined) {
if (!Number.isInteger(value.times) || value.times < 0) throw new Error("Rule times must be a non-negative integer.");
remaining = value.times;
}
const base = { kind: value.kind, pathPrefix, everyNth, remaining, matches: 0 };
if (value.kind === "latency") {
return { ...base, delayMs: nonNegativeNumber(value.delayMs, "Latency delayMs"), jitterMs: nonNegativeNumber(value.jitterMs ?? 0, "Latency jitterMs") };
}
if (value.kind === "status") {
const statusCode = positiveInteger(value.statusCode, "Status statusCode");
if (statusCode > 999) throw new Error("Status statusCode must be at most 999.");
return { ...base, statusCode, body: value.body };
}
if (value.kind === "reset" || value.kind === "stall") return base;
throw new Error(`Unsupported rule kind: ${value.kind}`);
}
function takeRule(path) {
for (const rule of rules) {
if (rule.remaining <= 0 || !path.startsWith(rule.pathPrefix)) continue;
rule.matches += 1;
if (rule.everyNth !== null && rule.matches % rule.everyNth !== 0) continue;
if (Number.isFinite(rule.remaining)) rule.remaining -= 1;
return rule;
}
return null;
}
function requestEntry(incoming, path, status, fault) {
requests.push({
method: incoming.method ?? "GET",
path,
status,
faulted: fault !== null,
...(fault === null ? {} : { fault }),
phase,
profile,
at: Date.now(),
});
}
function writeUpstreamResponse(client, response) {
const status = response.statusCode ?? 502;
const headers = forwardedHeaders(response.headers);
if (response.statusMessage) client.writeHead(status, response.statusMessage, headers);
else client.writeHead(status, headers);
}
async function pacedPipe(source, destination, rate) {
const chunkSize = Math.max(1, Math.min(Math.floor(rate / 10), 64 * 1024));
const intervalMs = 1_000 * chunkSize / rate;
for await (const value of source) {
const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
for (let offset = 0; offset < chunk.length; offset += chunkSize) {
destination.write(chunk.subarray(offset, Math.min(offset + chunkSize, chunk.length)));
await sleep(intervalMs);
}
}
destination.end();
}
function forward(incoming, client, path, fault) {
const requested = new URL(path, "http://request-target.invalid");
const options = {
protocol: upstream.protocol,
hostname: upstream.hostname,
port: upstream.port,
path: `${requested.pathname}${requested.search}`,
method: incoming.method ?? "GET",
headers: forwardedHeaders(incoming.headers, upstream.host),
};
const onResponse = (response) => {
const status = response.statusCode ?? 502;
requestEntry(incoming, path, status, fault ?? (bytesPerSec === null ? null : "bandwidth"));
writeUpstreamResponse(client, response);
const rate = bytesPerSec;
if (rate === null) {
response.pipe(client);
return;
}
void pacedPipe(response, client, rate).catch((error) => client.destroy(error));
};
const outbound = upstream.protocol === "https:"
? httpsRequest(options, onResponse)
: httpRequest(options, onResponse);
outbound.on("error", (error) => {
if (client.destroyed) return;
if (client.headersSent) {
client.destroy(error);
return;
}
requestEntry(incoming, path, 502, fault);
client.writeHead(502, { "content-type": "application/json" });
client.end(JSON.stringify({ error: error.message }));
});
incoming.on("aborted", () => outbound.destroy());
client.on("close", () => outbound.destroy());
incoming.pipe(outbound);
}
function destroyStalledSockets() {
for (const socket of stalledSockets) socket.destroy();
stalledSockets.clear();
}
function restoreOnline() {
if (offlineTimer !== null) clearTimeout(offlineTimer);
offlineTimer = null;
offline = false;
offlineUntil = null;
}
function activateOffline(durationMs) {
restoreOnline();
offline = true;
offlineUntil = Date.now() + durationMs;
for (const socket of dataSockets) socket.destroy();
stalledSockets.clear();
offlineTimer = setTimeout(restoreOnline, durationMs);
}
const dataServer = createServer((incoming, response) => {
void (async () => {
const path = incoming.url ?? "/";
const rule = takeRule(path);
if (rule?.kind === "status") {
const body = JSON.stringify(rule.body ?? { error: `Injected HTTP ${rule.statusCode}` });
requestEntry(incoming, path, rule.statusCode, "status");
response.writeHead(rule.statusCode, {
"access-control-allow-origin": "*",
"content-length": Buffer.byteLength(body),
"content-type": "application/json",
});
response.end(body);
return;
}
if (rule?.kind === "reset") {
requestEntry(incoming, path, 0, "reset");
response.destroy();
return;
}
if (rule?.kind === "stall") {
requestEntry(incoming, path, 0, "stall");
if (incoming.socket) {
stalledSockets.add(incoming.socket);
incoming.socket.once("close", () => stalledSockets.delete(incoming.socket));
}
incoming.resume();
return;
}
if (rule?.kind === "latency") {
const span = Math.floor(rule.jitterMs * 2) + 1;
const jitter = span > 1 ? (rule.matches * 1103515245 + 12345) % span - Math.floor(rule.jitterMs) : 0;
await sleep(Math.max(0, rule.delayMs + jitter));
}
if (response.destroyed) return;
forward(incoming, response, path, rule === null ? null : "latency");
})().catch((error) => {
if (response.destroyed) return;
if (response.headersSent) {
response.destroy(error instanceof Error ? error : undefined);
return;
}
response.writeHead(500, { "content-type": "application/json" });
response.end(JSON.stringify({ error: error instanceof Error ? error.message : String(error) }));
});
});
dataServer.prependListener("connection", (socket) => {
if (offline) {
refusedConnections[phase] = (refusedConnections[phase] ?? 0) + 1;
socket.destroy();
return;
}
dataSockets.add(socket);
socket.once("close", () => {
dataSockets.delete(socket);
stalledSockets.delete(socket);
});
});
function readJson(request) {
return new Promise((resolve, reject) => {
const chunks = [];
let length = 0;
request.on("data", (chunk) => {
length += chunk.length;
if (length > 1024 * 1024) {
reject(new Error("Admin request body is too large."));
request.destroy();
return;
}
chunks.push(chunk);
});
request.on("end", () => {
try {
resolve(chunks.length === 0 ? {} : JSON.parse(Buffer.concat(chunks).toString("utf8")));
} catch (error) {
reject(error);
}
});
request.on("error", reject);
});
}
function sendJson(response, status, body) {
const text = JSON.stringify(body);
response.writeHead(status, { "content-length": Buffer.byteLength(text), "content-type": "application/json" });
response.end(text);
}
function isAuthorized(request) {
const receivedHash = createHash("sha256").update(headerText(request.headers.authorization)).digest();
return timingSafeEqual(receivedHash, expectedAuthorizationHash);
}
const adminServer = createServer((request, response) => {
void (async () => {
if (!isAuthorized(request)) {
sendJson(response, 401, { error: "Unauthorized" });
return;
}
const path = new URL(request.url ?? "/", "http://admin.invalid").pathname;
if (request.method === "GET" && path === "/health") {
sendJson(response, 200, { ok: true, upstream: upstream.href, phase, profile, offline, offlineUntil, rules: rules.length });
return;
}
if (request.method === "GET" && path === "/requests") {
sendJson(response, 200, { requests, refusedConnections, phase, profile });
return;
}
if (request.method === "GET" && path === "/stats") {
sendJson(response, 200, {
requests: requests.length,
faults: requests.filter((entry) => entry.faulted).length,
refusedConnections: Object.values(refusedConnections).reduce((total, count) => total + count, 0),
phase,
profile,
});
return;
}
if (request.method !== "POST") {
sendJson(response, 404, { error: "Not found" });
return;
}
const body = await readJson(request);
if (!isRecord(body)) throw new Error("Admin body must be a JSON object.");
if (path === "/phase") {
if (typeof body.name !== "string" || body.name.length === 0) throw new Error("phase name must be a non-empty string.");
phase = body.name;
if (body.profile !== undefined) {
if (body.profile !== "baseline" && body.profile !== "vpn-flaky-emulated") throw new Error("profile must be baseline or vpn-flaky-emulated.");
profile = body.profile;
if (profile === "baseline") {
rules = [];
bytesPerSec = null;
} else {
// Check the periodic rekey-style reset first. Non-reset requests then
// fall through to the catch-all 300–800ms latency rule.
rules = [
normalizeRule({ kind: "reset", everyNth: 3 }),
normalizeRule({ kind: "latency", delayMs: 550, jitterMs: 250, everyNth: 1 }),
];
bytesPerSec = 256 * 1024;
}
}
} else if (path === "/rules") {
if (!Array.isArray(body.rules)) throw new Error("rules must be an array.");
rules = body.rules.map(normalizeRule);
} else if (path === "/bandwidth") {
if (body.bytesPerSec === null) bytesPerSec = null;
else bytesPerSec = positiveInteger(body.bytesPerSec, "bytesPerSec");
} else if (path === "/offline") {
activateOffline(nonNegativeNumber(body.durationMs, "durationMs"));
} else if (path === "/clear") {
rules = [];
bytesPerSec = null;
profile = "baseline";
restoreOnline();
destroyStalledSockets();
} else {
sendJson(response, 404, { error: "Not found" });
return;
}
sendJson(response, 200, { ok: true });
})().catch(() => {
if (!response.headersSent) sendJson(response, 400, { error: "Invalid request" });
else response.destroy();
});
});
adminServer.on("connection", (socket) => {
adminSockets.add(socket);
socket.once("close", () => adminSockets.delete(socket));
});
function listen(server, port, host) {
return new Promise((resolve, reject) => {
server.once("error", reject);
server.listen(port, host, resolve);
});
}
function close(server) {
return new Promise((resolve) => server.close(() => resolve()));
}
async function shutdown() {
if (shuttingDown) return;
shuttingDown = true;
restoreOnline();
for (const socket of dataSockets) socket.destroy();
for (const socket of adminSockets) socket.destroy();
await Promise.all([close(dataServer), close(adminServer)]);
}
process.on("SIGTERM", () => void shutdown().then(() => process.exit(0)));
process.on("SIGINT", () => void shutdown().then(() => process.exit(0)));
await Promise.all([
listen(dataServer, dataPort, "0.0.0.0"),
listen(adminServer, adminPort, "0.0.0.0"),
]);
console.log(`link-server listening data=${dataPort} admin=${adminPort} upstream=${upstream.href}`);
+407
View File
@@ -0,0 +1,407 @@
import { spawn } from "node:child_process";
import { randomBytes } from "node:crypto";
import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import { setTimeout as delay } from "node:timers/promises";
import { allocateFreePort } from "@openwork/cdp";
import { checkedExec, defaultDaytonaExec } from "@openwork/hosts";
import type { ChildProcess } from "node:child_process";
import type { DenRef } from "@openwork/behaviors";
import type { DaytonaExec } from "@openwork/hosts";
const DAYTONA_LINK_SCRIPT = "/tmp/openwork-den-link-server.mjs";
const DAYTONA_LINK_PID = "/tmp/openwork-den-link-server.pid";
const DAYTONA_LINK_BASE64 = `${DAYTONA_LINK_SCRIPT}.b64`;
const MAX_LINK_SCRIPT_BYTES = 512 * 1024;
const DAYTONA_LINK_BASE64_CHUNK_LENGTH = 8 * 1024;
/** Conservative ceiling for each complete Daytona argv command string. */
export const MAX_LINK_DAYTONA_COMMAND_LENGTH = 12 * 1024;
export type LinkRule = { pathPrefix?: string; times?: number; everyNth?: number } & (
| { kind: "latency"; delayMs: number; jitterMs?: number }
| { kind: "status"; statusCode: number; body?: unknown }
| { kind: "reset" }
| { kind: "stall" }
);
export type LinkProfile = "baseline" | "vpn-flaky-emulated";
export type DenLinkClient = "public-preview" | "sandbox-loopback";
export interface LinkRequestEntry {
method: string;
path: string;
status: number;
faulted: boolean;
fault?: string;
phase: string;
profile: LinkProfile;
at: number;
}
export interface LinkLog {
requests: LinkRequestEntry[];
refusedConnections: Record<string, number>;
phase: string;
profile: LinkProfile;
}
export interface LinkStats {
requests: number;
faults: number;
refusedConnections: number;
phase: string;
profile: LinkProfile;
}
export interface DenLink extends AsyncDisposable {
/** Den ref as seen by the app: webUrl is the shaped data URL. */
ref: DenRef;
admin: {
phase(name: string, profile?: LinkProfile): Promise<void>;
rules(rules: LinkRule[]): Promise<void>;
bandwidth(bytesPerSec: number | null): Promise<void>;
offline(durationMs: number): Promise<void>;
clear(): Promise<void>;
requests(): Promise<LinkLog>;
stats(): Promise<LinkStats>;
health(): Promise<{ ok: boolean; phase: string; offline: boolean }>;
};
}
export interface DenLinkOptions {
/** Run in this known Daytona sandbox, normally `den.placement.sandboxId`. Omit for a local child process. */
sandboxId?: string;
/** URL exposed to the app for Daytona placement. Defaults to the public data preview. */
client?: DenLinkClient;
/** Fixed in-sandbox ports; defaults 3985 (data) / 3986 (admin). Local placement allocates free ports and ignores these. */
port?: number;
adminPort?: number;
/** Override Daytona command execution, primarily for deterministic tests. */
daytonaExec?: DaytonaExec;
}
interface LinkPlacement {
dataUrl: string;
adminUrl: string;
dispose(): Promise<void>;
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function messageText(error: unknown): string {
return error instanceof Error ? error.message : String(error);
}
function isProfile(value: unknown): value is LinkProfile {
return value === "baseline" || value === "vpn-flaky-emulated";
}
function parseHealth(value: unknown): { ok: boolean; phase: string; offline: boolean } {
if (isRecord(value) && typeof value.ok === "boolean" && typeof value.phase === "string" && typeof value.offline === "boolean") {
return { ok: value.ok, phase: value.phase, offline: value.offline };
}
throw new Error("Link health response has an invalid shape.");
}
function parseRequestEntry(value: unknown): LinkRequestEntry {
if (!isRecord(value)
|| typeof value.method !== "string"
|| typeof value.path !== "string"
|| typeof value.status !== "number"
|| typeof value.faulted !== "boolean"
|| (value.fault !== undefined && typeof value.fault !== "string")
|| typeof value.phase !== "string"
|| !isProfile(value.profile)
|| typeof value.at !== "number") {
throw new Error("Link request entry has an invalid shape.");
}
return {
method: value.method,
path: value.path,
status: value.status,
faulted: value.faulted,
...(value.fault === undefined ? {} : { fault: value.fault }),
phase: value.phase,
profile: value.profile,
at: value.at,
};
}
function parseLog(value: unknown): LinkLog {
if (!isRecord(value) || !Array.isArray(value.requests) || !isRecord(value.refusedConnections) || typeof value.phase !== "string" || !isProfile(value.profile)) {
throw new Error("Link requests response has an invalid shape.");
}
const refusedConnections: Record<string, number> = {};
for (const [name, count] of Object.entries(value.refusedConnections)) {
if (typeof count !== "number") throw new Error("Link refusal count has an invalid shape.");
refusedConnections[name] = count;
}
return { requests: value.requests.map(parseRequestEntry), refusedConnections, phase: value.phase, profile: value.profile };
}
function parseStats(value: unknown): LinkStats {
if (!isRecord(value)
|| typeof value.requests !== "number"
|| typeof value.faults !== "number"
|| typeof value.refusedConnections !== "number"
|| typeof value.phase !== "string"
|| !isProfile(value.profile)) {
throw new Error("Link stats response has an invalid shape.");
}
return {
requests: value.requests,
faults: value.faults,
refusedConnections: value.refusedConnections,
phase: value.phase,
profile: value.profile,
};
}
async function adminJson(baseUrl: string, path: string, token: string, body?: object): Promise<unknown> {
const response = await fetch(`${baseUrl}${path}`, {
method: body === undefined ? "GET" : "POST",
headers: {
authorization: `Bearer ${token}`,
...(body === undefined ? {} : { "content-type": "application/json" }),
},
body: body === undefined ? undefined : JSON.stringify(body),
signal: AbortSignal.timeout(10_000),
});
const text = await response.text();
if (!response.ok) throw new Error(`Den link admin ${path} failed with HTTP ${response.status}: ${text.slice(0, 1_000)}`);
try {
return JSON.parse(text);
} catch {
throw new Error(`Den link admin ${path} returned invalid JSON: ${text.slice(0, 1_000)}`);
}
}
async function distinctLocalPorts(): Promise<[number, number]> {
const port = await allocateFreePort();
let adminPort = await allocateFreePort();
while (adminPort === port) adminPort = await allocateFreePort();
return [port, adminPort];
}
function waitForExit(child: ChildProcess): Promise<void> {
if (child.exitCode !== null || child.signalCode !== null) return Promise.resolve();
return new Promise((resolve) => child.once("exit", () => resolve()));
}
async function localPlacement(upstream: DenRef, token: string): Promise<LinkPlacement> {
const [port, adminPort] = await distinctLocalPorts();
const script = fileURLToPath(new URL("./link-server.mjs", import.meta.url));
const child = spawn(process.execPath, [script, "--upstream", upstream.webUrl, "--port", String(port), "--admin-port", String(adminPort)], {
env: { ...process.env, LINK_ADMIN_TOKEN: token },
stdio: ["ignore", "pipe", "pipe"],
});
if (!child.stdout || !child.stderr) throw new Error("Den link child process did not expose output streams.");
let output = "";
child.stdout.setEncoding("utf8");
child.stderr.setEncoding("utf8");
child.stdout.on("data", (chunk) => { output += String(chunk); });
child.stderr.on("data", (chunk) => { output += String(chunk); });
const listening = `link-server listening data=${port} admin=${adminPort}`;
try {
const deadline = Date.now() + 15_000;
while (!output.includes(listening) && Date.now() < deadline) {
if (child.exitCode !== null) throw new Error(`Den link exited during startup (${child.exitCode}): ${output.slice(-2_000)}`);
await delay(50);
}
if (!output.includes(listening)) throw new Error(`Timed out waiting for Den link startup: ${output.slice(-2_000)}`);
await adminJson(`http://127.0.0.1:${adminPort}`, "/health", token);
} catch (error) {
child.kill("SIGKILL");
throw error;
}
let disposed = false;
return {
dataUrl: `http://127.0.0.1:${port}`,
adminUrl: `http://127.0.0.1:${adminPort}`,
async dispose(): Promise<void> {
if (disposed) return;
disposed = true;
child.kill("SIGTERM");
const exited = waitForExit(child);
await Promise.race([exited, delay(5_000)]);
if (child.exitCode === null && child.signalCode === null) {
child.kill("SIGKILL");
await waitForExit(child);
}
},
};
}
function safeRemoteUrl(value: string): string {
const parsed = new URL(value);
if ((parsed.protocol !== "http:" && parsed.protocol !== "https:") || !/^[A-Za-z0-9:/?&=._~%+\-]+$/.test(value)) {
throw new Error(`Den link upstream URL is not safe for Daytona execution: ${value}`);
}
return value;
}
function validPort(value: number, name: string): number {
if (!Number.isInteger(value) || value < 1 || value > 65_535) throw new Error(`${name} must be a valid port.`);
return value;
}
async function remoteExec(exec: DaytonaExec, sandbox: string, script: string, context: string, timeoutMs = 30_000): Promise<string> {
if (script.includes("'")) throw new Error(`Remote script for ${context} must not contain single quotes.`);
const args = ["exec", sandbox, "--", `bash -lc '${script}'`];
const commandLength = args.join(" ").length;
if (commandLength > MAX_LINK_DAYTONA_COMMAND_LENGTH) {
throw new Error(`Den link Daytona command is ${commandLength} characters; maximum is ${MAX_LINK_DAYTONA_COMMAND_LENGTH}.`);
}
const result = await checkedExec(exec, args, context, { timeoutMs });
return `${result.stdout}${result.stderr}`;
}
function firstHttpsUrl(text: string): string | null {
const match = /https:\/\/[^\s"'<>)]+/.exec(text);
return match ? match[0].replace(/[.,;:]+$/, "") : null;
}
export function daytonaLinkCommands(
source: Uint8Array,
upstream: string,
port: number,
adminPort: number,
token: string,
): { cleanup: string; upload: string[]; detach: string } {
if (source.byteLength === 0 || source.byteLength > MAX_LINK_SCRIPT_BYTES) {
throw new Error(`Den link runner must be between 1 and ${MAX_LINK_SCRIPT_BYTES} bytes.`);
}
const upstreamUrl = safeRemoteUrl(upstream);
const dataPort = validPort(port, "port");
const controlPort = validPort(adminPort, "adminPort");
if (!/^[a-f0-9]{32,}$/.test(token)) throw new Error("Den link admin token must be at least 32 lowercase hex characters.");
const encoded = Buffer.from(source).toString("base64");
const upload = [`: > ${DAYTONA_LINK_BASE64}`];
for (let offset = 0; offset < encoded.length; offset += DAYTONA_LINK_BASE64_CHUNK_LENGTH) {
const chunk = encoded.slice(offset, offset + DAYTONA_LINK_BASE64_CHUNK_LENGTH);
upload.push(`printf %s ${chunk} >> ${DAYTONA_LINK_BASE64}`);
}
upload.push([
"decode_status=0",
`base64 -d ${DAYTONA_LINK_BASE64} > ${DAYTONA_LINK_SCRIPT} || decode_status=$?`,
`actual_bytes=$(wc -c < ${DAYTONA_LINK_SCRIPT})`,
`rm -f ${DAYTONA_LINK_BASE64}`,
'test "$decode_status" -eq 0',
`test "$actual_bytes" -eq ${source.byteLength}`,
].join("; "));
return {
cleanup: `if test -f ${DAYTONA_LINK_PID}; then pid=$(<${DAYTONA_LINK_PID}); case "$pid" in ""|*[!0-9]*) ;; *) if test "$pid" -gt 0 2>/dev/null; then kill "$pid" 2>/dev/null || true; attempts=0; while kill -0 "$pid" 2>/dev/null && test "$attempts" -lt 50; do sleep 0.1; attempts=$((attempts + 1)); done; fi ;; esac; fi; rm -f ${DAYTONA_LINK_PID} ${DAYTONA_LINK_SCRIPT} ${DAYTONA_LINK_BASE64}`,
upload,
detach: `python3 - <<PYEOF
import os
import subprocess
log = open("/tmp/link-server.log", "ab", buffering=0)
process = subprocess.Popen(["node", "${DAYTONA_LINK_SCRIPT}", "--upstream", "${upstreamUrl}", "--port", "${dataPort}", "--admin-port", "${controlPort}"], stdin=subprocess.DEVNULL, stdout=log, stderr=subprocess.STDOUT, start_new_session=True, close_fds=True, env={**os.environ, "LINK_ADMIN_TOKEN": "${token}"})
temporary_pid = "${DAYTONA_LINK_PID}." + str(os.getpid())
try:
with open(temporary_pid, "w", encoding="ascii") as pid_file:
pid_file.write(str(process.pid) + "\\n")
pid_file.flush()
os.fsync(pid_file.fileno())
os.replace(temporary_pid, "${DAYTONA_LINK_PID}")
except Exception:
try:
os.unlink(temporary_pid)
except FileNotFoundError:
pass
process.terminate()
raise
PYEOF`,
};
}
async function daytonaPlacement(upstream: DenRef, sandbox: string, options: DenLinkOptions, token: string): Promise<LinkPlacement> {
const exec = options.daytonaExec ?? defaultDaytonaExec;
const port = validPort(options.port ?? 3985, "port");
const adminPort = validPort(options.adminPort ?? 3986, "adminPort");
const client = options.client ?? "public-preview";
if (port === adminPort) throw new Error("Den link data and admin ports must differ.");
// Pin the original public Den URL before creating the shaper preview URLs;
// running inside that Den sandbox therefore cannot proxy back into itself.
const upstreamUrl = safeRemoteUrl(upstream.webUrl);
const source = await readFile(fileURLToPath(new URL("./link-server.mjs", import.meta.url)));
const commands = daytonaLinkCommands(source, upstreamUrl, port, adminPort, token);
const cleanup = (): Promise<string> => remoteExec(exec, sandbox, commands.cleanup, `Den link cleanup for ${sandbox}`);
await cleanup();
try {
for (const [index, upload] of commands.upload.entries()) {
await remoteExec(exec, sandbox, upload, `Den link upload ${index + 1}/${commands.upload.length} for ${sandbox}`, 30_000);
}
await remoteExec(exec, sandbox, commands.detach, `Den link detach for ${sandbox}`);
const deadline = Date.now() + 60_000;
let last = "not attempted";
while (Date.now() < deadline) {
try {
await remoteExec(exec, sandbox, `curl -sf -H "Authorization: Bearer ${token}" http://127.0.0.1:${adminPort}/health`, `Den link health for ${sandbox}`, 10_000);
last = "ok";
break;
} catch (error) {
last = messageText(error);
await delay(1_000);
}
}
if (last !== "ok") {
const log = await remoteExec(exec, sandbox, "tail -80 /tmp/link-server.log 2>&1 || true", `Den link log for ${sandbox}`).catch((error: unknown) => messageText(error));
throw new Error(`Den link health gate failed in ${sandbox}. Last: ${last}. Log tail:\n${log.slice(-4_000)}`);
}
const dataPreview = client === "public-preview"
? await checkedExec(exec, ["preview-url", sandbox, "-p", String(port)], `daytona preview-url ${sandbox} -p ${port}`, { timeoutMs: 30_000 })
: null;
const adminPreview = await checkedExec(exec, ["preview-url", sandbox, "-p", String(adminPort)], `daytona preview-url ${sandbox} -p ${adminPort}`, { timeoutMs: 30_000 });
const dataUrl = dataPreview ? firstHttpsUrl(dataPreview.stdout) : `http://127.0.0.1:${port}`;
const adminUrl = firstHttpsUrl(adminPreview.stdout);
if (!dataUrl) throw new Error(`daytona preview-url ${sandbox} -p ${port} did not print an https URL: ${dataPreview?.stdout.trim()}`);
if (!adminUrl) throw new Error(`daytona preview-url ${sandbox} -p ${adminPort} did not print an https URL: ${adminPreview.stdout.trim()}`);
await adminJson(adminUrl, "/health", token);
let disposed = false;
return {
dataUrl,
adminUrl,
async dispose(): Promise<void> {
if (disposed) return;
disposed = true;
await cleanup().catch((error: unknown) => console.error(`Den link cleanup failed for ${sandbox}: ${messageText(error)}`));
},
};
} catch (error) {
await cleanup().catch(() => undefined);
throw error;
}
}
export async function denLink(upstream: DenRef, options: DenLinkOptions = {}): Promise<DenLink> {
const token = randomBytes(32).toString("hex");
const placement = options.sandboxId
? await daytonaPlacement(upstream, options.sandboxId, options, token)
: await localPlacement(upstream, token);
const post = async (path: string, body: object): Promise<void> => {
await adminJson(placement.adminUrl, path, token, body);
};
return {
ref: { apiUrl: `${placement.dataUrl}/api/den`, webUrl: placement.dataUrl },
admin: {
phase: (name, profile) => post("/phase", profile === undefined ? { name } : { name, profile }),
rules: (newRules) => post("/rules", { rules: newRules }),
bandwidth: (rate) => post("/bandwidth", { bytesPerSec: rate }),
offline: (durationMs) => post("/offline", { durationMs }),
clear: () => post("/clear", {}),
async requests(): Promise<LinkLog> {
return parseLog(await adminJson(placement.adminUrl, "/requests", token));
},
async stats(): Promise<LinkStats> {
return parseStats(await adminJson(placement.adminUrl, "/stats", token));
},
async health(): Promise<{ ok: boolean; phase: string; offline: boolean }> {
return parseHealth(await adminJson(placement.adminUrl, "/health", token));
},
},
[Symbol.asyncDispose]: () => placement.dispose(),
};
}
+254
View File
@@ -0,0 +1,254 @@
import { execFile, spawn } from "node:child_process";
import { closeSync, openSync } from "node:fs";
import { mkdir, readFile } from "node:fs/promises";
import { join } from "node:path";
import { setTimeout as delay } from "node:timers/promises";
import { fileURLToPath } from "node:url";
import { promisify } from "node:util";
import { allocateFreePorts } from "@openwork/cdp";
import { SkipError, ephemeralDatabaseName, localMysqlIsRunning, localRedisIsRunning, trustedOrigins } from "@openwork/env";
import { freePort, killLocalPid } from "@openwork/hosts";
import type { ChildProcess } from "node:child_process";
import type { DenRef } from "@openwork/behaviors";
import type { DbHandle, Place } from "@openwork/env";
const execFileAsync = promisify(execFile);
const REPO_ROOT = fileURLToPath(new URL("../../../..", import.meta.url));
const DATABASE_ENCRYPTION_KEY = "local-dev-db-encryption-key-please-change-1234567890";
const BETTER_AUTH_SECRET = "local-testkit-secret-not-for-production-use!!";
const START_TIMEOUT_MS = 120_000;
export interface SelfHostServerOptions {
place: Place;
name: string;
slug: string;
ownerEmails: string[];
allowPublicSignup?: boolean;
}
export interface SelfHostDen {
ref: DenRef;
database: string;
}
interface SpawnedService {
child: ChildProcess;
pid: number;
port: number;
label: string;
logPath: string;
}
function messageText(error: unknown): string {
return error instanceof Error ? error.message : String(error);
}
function cleanUrl(value: string): string {
let out = value.trim();
while (out.endsWith("/")) out = out.slice(0, -1);
return out;
}
// mirrored from server.ts (keep in sync)
function spawnService(
label: string,
script: "dev:den:api" | "dev:den:web",
port: number,
env: NodeJS.ProcessEnv,
logPath: string,
): SpawnedService {
const logFd = openSync(logPath, "a");
const prepared = process.env.OPENWORK_EVAL_DEN_RUNTIME_PREPARED === "1";
const args = prepared
? label === "den-api"
? ["--filter", "@openwork-ee/den-api", "exec", "tsx", "src/main.ts"]
: ["--filter", "@openwork-ee/den-web", "exec", "next", "start", "--hostname", "127.0.0.1", "--port", String(port)]
: [script];
const child = spawn("pnpm", args, {
cwd: REPO_ROOT,
env: prepared && label === "den-api" ? { ...env, PORT: String(port) } : env,
detached: true,
stdio: ["ignore", logFd, logFd],
});
closeSync(logFd);
child.unref();
if (!child.pid) throw new Error(`Could not start ${label}.`);
return { child, pid: child.pid, port, label, logPath };
}
// mirrored from server.ts (keep in sync)
async function logTail(path: string): Promise<string> {
return readFile(path, "utf8")
.then((text) => text.split(/\r?\n/).slice(-40).join("\n"))
.catch((error: unknown) => `log unavailable: ${messageText(error)}`);
}
// mirrored from server.ts (keep in sync)
async function waitForHttp(url: string, service: SpawnedService, accept: (response: Response) => boolean): Promise<Response> {
const deadline = Date.now() + START_TIMEOUT_MS;
let last = "not attempted";
while (Date.now() < deadline) {
if (service.child.exitCode !== null) {
throw new Error(`${service.label} exited with ${service.child.exitCode}. Last log lines:\n${await logTail(service.logPath)}`);
}
try {
const response = await fetch(url, { signal: AbortSignal.timeout(5_000) });
if (accept(response)) return response;
last = `HTTP ${response.status}`;
} catch (error) {
last = messageText(error);
}
await delay(500);
}
throw new Error(`Timed out waiting for ${service.label} at ${url}: ${last}. Last log lines:\n${await logTail(service.logPath)}`);
}
// mirrored from server.ts (keep in sync)
async function waitForAuthProbe(ref: DenRef, service: SpawnedService): Promise<void> {
const url = `${cleanUrl(ref.apiUrl)}/api/auth/sign-in/email`;
const deadline = Date.now() + START_TIMEOUT_MS;
let last = "not attempted";
while (Date.now() < deadline) {
try {
const response = await fetch(url, {
method: "POST",
headers: { "content-type": "application/json", origin: ref.webUrl },
body: JSON.stringify({ email: `probe-${Date.now()}@openwork.test`, password: "not-a-real-password" }),
signal: AbortSignal.timeout(5_000),
});
if (response.status !== 403 && response.status < 500) return;
last = `HTTP ${response.status} ${(await response.text()).slice(0, 300)}`;
} catch (error) {
last = messageText(error);
}
await delay(500);
}
throw new Error(`Den auth behavioral probe failed at ${url}; expected a non-403 response. Last: ${last}. Log:\n${await logTail(service.logPath)}`);
}
// mirrored from server.ts (keep in sync)
async function runDbPush(databaseUrl: string): Promise<void> {
try {
const commands = process.env.OPENWORK_EVAL_DEN_RUNTIME_PREPARED === "1"
? [
["--filter", "@openwork-ee/den-db", "exec", "node", "--import", "tsx", "./node_modules/drizzle-kit/bin.cjs", "push", "--config", "drizzle.config.ts"],
["--filter", "@openwork-ee/den-db", "exec", "node", "--import", "tsx", "scripts/ensure-schema-repairs.ts"],
]
: [["--filter", "@openwork-ee/den-db", "db:push"]];
for (const args of commands) {
await execFileAsync("pnpm", args, {
cwd: REPO_ROOT,
env: {
...process.env,
DATABASE_URL: databaseUrl,
DEN_DB_ENCRYPTION_KEY: DATABASE_ENCRYPTION_KEY,
},
maxBuffer: 16 * 1024 * 1024,
timeout: 180_000,
});
}
} catch (error) {
const stderr = typeof error === "object" && error !== null && typeof Reflect.get(error, "stderr") === "string"
? Reflect.get(error, "stderr")
: "";
throw new Error(`Ephemeral Den database push failed: ${messageText(error)}${stderr ? `\n${stderr}` : ""}`);
}
}
// mirrored from server.ts (keep in sync)
async function stopServices(services: SpawnedService[]): Promise<void> {
for (const service of services) {
await killLocalPid(service.pid, { log: (line) => console.error(`[openwork/testkit] ${line}`) })
.catch((error: unknown) => console.error(`[openwork/testkit] ${service.label} cleanup failed: ${messageText(error)}`));
await freePort(service.port)
.catch((error: unknown) => console.error(`[openwork/testkit] ${service.label} port cleanup failed: ${messageText(error)}`));
}
}
export async function selfHostServer(options: SelfHostServerOptions): Promise<SelfHostDen & AsyncDisposable> {
if (options.place.kind === "daytona") {
throw new SkipError("selfHostServer requires local placement; unset OPENWORK_EVAL_DAYTONA");
}
if (!await localMysqlIsRunning()) {
throw new Error("Local Den requires MySQL on 127.0.0.1:3306. Run: pnpm dev:den:mysql");
}
if (!await localRedisIsRunning()) {
throw new Error("Local Den requires Redis on 127.0.0.1:6379. Run: redis-server --port 6379 --daemonize yes --save '' --appendonly no");
}
const services: SpawnedService[] = [];
let database: DbHandle | undefined;
try {
database = await options.place.db(ephemeralDatabaseName("openwork_selfhost_eval"));
await runDbPush(database.url);
const [apiPort, webPort] = await allocateFreePorts(2);
if (apiPort === undefined || webPort === undefined) throw new Error("Could not allocate Den API/Web ports.");
const origins = trustedOrigins(apiPort, webPort).join(",");
const ref: DenRef = {
apiUrl: `http://127.0.0.1:${apiPort}`,
webUrl: `http://127.0.0.1:${webPort}`,
};
const logsDir = join(REPO_ROOT, "evals", "results", ".testkit", database.name);
await mkdir(logsDir, { recursive: true });
const commonEnv: NodeJS.ProcessEnv = {
...process.env,
DATABASE_URL: database.url,
DEN_DB_ENCRYPTION_KEY: DATABASE_ENCRYPTION_KEY,
BETTER_AUTH_SECRET,
BETTER_AUTH_URL: `http://localhost:${webPort}`,
DEN_BASE_URL: `http://localhost:${webPort}`,
DEN_API_PUBLIC_URL: ref.apiUrl,
DEN_API_PORT: String(apiPort),
DEN_WEB_PORT: String(webPort),
DEN_BETTER_AUTH_TRUSTED_ORIGINS: origins,
CORS_ORIGINS: origins,
DEN_ORG_MODE: "single_org",
DEN_SINGLE_ORG_NAME: options.name,
DEN_SINGLE_ORG_SLUG: options.slug,
DEN_SINGLE_ORG_OWNER_EMAILS: options.ownerEmails.join(","),
DEN_SINGLE_ORG_ALLOW_PUBLIC_SIGNUP: String(options.allowPublicSignup ?? false),
DEN_REQUIRE_EMAIL_VERIFICATION: "false",
DEN_PASSWORD_BREACH_SCREENING_ENABLED: "false",
OPENWORK_DEV_MODE: "1",
PROVISIONER_MODE: "stub",
};
const api = spawnService("den-api", "dev:den:api", apiPort, {
...commonEnv,
DEN_BIND_HOST: "127.0.0.1",
}, join(logsDir, "api.log"));
services.push(api);
const web = spawnService("den-web", "dev:den:web", webPort, {
DEN_WEB_HOST: "127.0.0.1",
...commonEnv,
DEN_API_BASE: `http://127.0.0.1:${apiPort}`,
DEN_BASE_URL: `http://localhost:${webPort}`,
DEN_AUTH_ORIGIN: `http://localhost:${webPort}`,
DEN_AUTH_FALLBACK_BASE: `http://127.0.0.1:${apiPort}`,
}, join(logsDir, "web.log"));
services.push(web);
await waitForHttp(`${ref.apiUrl}/health`, api, (response) => response.ok);
await waitForHttp(`${ref.webUrl}/api/ready`, web, (response) => response.ok);
await waitForAuthProbe(ref, api);
let disposed = false;
return {
ref,
database: database.name,
async [Symbol.asyncDispose](): Promise<void> {
if (disposed) return;
disposed = true;
await stopServices(services);
await database?.drop().catch((error: unknown) => {
console.error(`[openwork/testkit] ephemeral database cleanup failed: ${messageText(error)}`);
});
},
};
} catch (error) {
await stopServices(services);
await database?.drop().catch(() => undefined);
throw error;
}
}
+7
View File
@@ -0,0 +1,7 @@
export * from "@openwork/behaviors";
export * from "@openwork/hosts";
export * from "@openwork/env";
export * from "./eventually.ts";
export * from "./link.ts";
export * from "./self-host.ts";
export * from "./state.ts";
+263
View File
@@ -0,0 +1,263 @@
import { readFile } from "node:fs/promises";
import { join, posix } from "node:path";
import { evalIn } from "@openwork/behaviors";
import { defaultDaytonaExec, electronProfilePaths, execInSandbox } from "@openwork/hosts";
import type { Surface } from "@openwork/cdp";
export interface DenClientState {
authTokenPresent: boolean;
activeOrgId: string | null;
activeOrgSlug: string | null;
activeOrgName: string | null;
}
export interface ConnectState {
ok: boolean;
status: "available" | "missing" | "invalid" | "unreadable" | null;
connectEnabled: boolean | null;
raw: unknown;
}
export interface CloudMcpHealthSummary {
ok: boolean;
phase: string | null;
usable: boolean | null;
engineStatus: string | null;
tools: { present: string[]; missing: string[] };
direct: { checked: boolean; source: string | null; present: string[]; missing: string[] };
raw: unknown;
}
export interface ConnectStateFile {
status: "missing" | "available" | "invalid";
connectEnabled: boolean | null;
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function nullableString(value: unknown): string | null {
return typeof value === "string" && value.trim() ? value.trim() : null;
}
function stringArray(value: unknown): string[] {
return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : [];
}
function errorCode(error: unknown): string | null {
return isRecord(error) && typeof error.code === "string" ? error.code : null;
}
export async function readDenClientState(app: Surface): Promise<DenClientState> {
const value = await evalIn(app, `(() => ({
authTokenPresent: Boolean((localStorage.getItem("openwork.den.authToken") ?? "").trim()),
activeOrgId: (localStorage.getItem("openwork.den.activeOrgId") ?? "").trim() || null,
activeOrgSlug: (localStorage.getItem("openwork.den.activeOrgSlug") ?? "").trim() || null,
activeOrgName: (localStorage.getItem("openwork.den.activeOrgName") ?? "").trim() || null,
}))()`);
if (!isRecord(value)) throw new Error("The desktop returned an invalid Den client state.");
return {
authTokenPresent: value.authTokenPresent === true,
activeOrgId: nullableString(value.activeOrgId),
activeOrgSlug: nullableString(value.activeOrgSlug),
activeOrgName: nullableString(value.activeOrgName),
};
}
export async function readConnectState(app: Surface): Promise<ConnectState> {
const value = await evalIn(app, `(async () => {
// Resolve the local server the same way the app does: live runtime info
// from the Electron bridge first (loopback port + token are ephemeral per
// boot), then the web-mode localStorage overrides as a fallback.
let baseUrl = "";
let token = "";
try {
const invokeDesktop = window.__OPENWORK_ELECTRON__ && window.__OPENWORK_ELECTRON__.invokeDesktop;
if (invokeDesktop) {
const info = await invokeDesktop("openworkServerInfo");
if (info && info.running === true) {
baseUrl = String(info.baseUrl ?? info.connectUrl ?? "").trim().replace(/\\/+$/, "");
token = String(info.ownerToken ?? info.clientToken ?? "").trim();
}
}
} catch {}
if (!baseUrl || !token) {
const port = (localStorage.getItem("openwork.server.port") ?? "").trim();
baseUrl = port ? "http://127.0.0.1:" + port : baseUrl;
token = token || (localStorage.getItem("openwork.server.token") ?? "").trim();
}
if (!baseUrl || !token) {
return { ok: false, status: null, connectEnabled: null, raw: { error: "Local server credentials are unavailable." } };
}
try {
const response = await fetch(
baseUrl + "/experimental/connect/state",
{ headers: { Authorization: "Bearer " + token } },
);
const text = await response.text();
let raw = text;
try { raw = text ? JSON.parse(text) : null; } catch {}
return {
ok: response.ok,
status: raw && typeof raw === "object"
&& (raw.status === "available" || raw.status === "missing" || raw.status === "invalid" || raw.status === "unreadable")
? raw.status
: null,
connectEnabled: raw && typeof raw === "object" && typeof raw.connectEnabled === "boolean"
? raw.connectEnabled
: null,
raw,
};
} catch (error) {
return {
ok: false,
status: null,
connectEnabled: null,
raw: { error: error instanceof Error ? error.message : String(error) },
};
}
})()`, { awaitPromise: true, timeoutMs: 15_000 });
if (!isRecord(value)) throw new Error("The desktop returned an invalid Connect state.");
return {
ok: value.ok === true,
status: value.status === "available" || value.status === "missing" || value.status === "invalid" || value.status === "unreadable"
? value.status
: null,
connectEnabled: typeof value.connectEnabled === "boolean" ? value.connectEnabled : null,
raw: value.raw,
};
}
export async function readCloudMcpHealth(
app: Surface,
workspaceId: string,
opts?: { probe?: boolean; timeoutMs?: number },
): Promise<CloudMcpHealthSummary> {
const value = await evalIn(app, `(async () => {
// Resolve the local server the same way the app does: live runtime info
// from the Electron bridge first (loopback port + token are ephemeral per
// boot), then the web-mode localStorage overrides as a fallback.
let baseUrl = "";
let token = "";
try {
const invokeDesktop = window.__OPENWORK_ELECTRON__ && window.__OPENWORK_ELECTRON__.invokeDesktop;
if (invokeDesktop) {
const info = await invokeDesktop("openworkServerInfo");
if (info && info.running === true) {
baseUrl = String(info.baseUrl ?? info.connectUrl ?? "").trim().replace(/\\/+$/, "");
token = String(info.ownerToken ?? info.clientToken ?? "").trim();
}
}
} catch {}
if (!baseUrl || !token) {
const port = (localStorage.getItem("openwork.server.port") ?? "").trim();
baseUrl = port ? "http://127.0.0.1:" + port : baseUrl;
token = token || (localStorage.getItem("openwork.server.token") ?? "").trim();
}
if (!baseUrl || !token) {
return { ok: false, raw: { error: "Local server credentials are unavailable." } };
}
try {
const response = await fetch(
baseUrl + "/workspace/" + encodeURIComponent(${JSON.stringify(workspaceId)}) + "/mcp/openwork-cloud/health" + ${JSON.stringify(opts?.probe === true ? "?probe=1" : "")},
{ headers: { Authorization: "Bearer " + token } },
);
const text = await response.text();
let raw = text;
try { raw = text ? JSON.parse(text) : null; } catch {}
return { ok: response.ok, raw };
} catch (error) {
return {
ok: false,
raw: { error: error instanceof Error ? error.message : String(error) },
};
}
})()`, { awaitPromise: true, timeoutMs: opts?.timeoutMs ?? 15_000 });
const result = isRecord(value) ? value : {};
const raw = result.raw;
const health = isRecord(raw) ? raw : {};
const engine = isRecord(health.engine) ? health.engine : {};
const tools = isRecord(health.tools) ? health.tools : {};
const direct = isRecord(tools.direct) ? tools.direct : {};
return {
ok: result.ok === true,
phase: nullableString(health.phase),
usable: typeof health.usable === "boolean" ? health.usable : null,
engineStatus: nullableString(engine.status),
tools: {
present: stringArray(tools.present),
missing: stringArray(tools.missing),
},
direct: {
checked: direct.checked === true,
source: nullableString(direct.source),
present: stringArray(direct.present),
missing: stringArray(direct.missing),
},
raw,
};
}
/** Reads the caller-visible profile filesystem. */
export async function readConnectStateFile(
app: Surface,
deps?: { exec?: (sandbox: string, script: string) => Promise<string> },
): Promise<ConnectStateFile> {
if (app.handle.hostKind !== "local" && app.handle.hostKind !== "daytona") {
throw new Error(`readConnectStateFile supports local and daytona app profiles; received ${app.handle.hostKind}.`);
}
if (!app.handle.profileDir) throw new Error(`The ${app.handle.hostKind} app did not expose its profile directory.`);
// The local server persists runtime state next to its config file
// (`openworkConfigDir()`). The dev-mode desktop redirects that XDG config
// root under its Electron userData dir (`<userData>/openwork-dev-data/xdg/config`),
// so probe the known layouts in order.
const paths = electronProfilePaths(app.handle.profileDir);
const pathJoin = app.handle.hostKind === "daytona" ? posix.join : join;
const candidates = [
pathJoin(paths.userDataDir, "openwork-dev-data", "xdg", "config", "openwork", "connect-state.json"),
pathJoin(paths.configHome, "openwork", "connect-state.json"),
pathJoin(paths.homeDir, ".config", "openwork", "connect-state.json"),
];
let text: string | null = null;
if (app.handle.hostKind === "daytona") {
if (!app.handle.sandboxId) throw new Error("The daytona app did not expose its sandbox ID.");
const sandbox = app.handle.sandboxId;
const exec = deps?.exec ?? (async (sandboxId: string, script: string): Promise<string> => {
const result = await execInSandbox(defaultDaytonaExec, sandboxId, script, {
timeoutMs: 30_000,
context: `connect-state read for ${sandboxId}`,
});
return result.stdout;
});
for (const path of candidates) {
if (!/^\/[A-Za-z0-9._/-]+$/.test(path)) {
throw new Error(`Unsafe connect-state path ${JSON.stringify(path)}: only absolute paths containing letters, digits and . _ / - are allowed.`);
}
const output = await exec(sandbox, `if [ -f "${path}" ]; then cat "${path}"; else echo __OPENWORK_TESTKIT_MISSING__; fi`);
if (output.trim() !== "__OPENWORK_TESTKIT_MISSING__") {
text = output;
break;
}
}
} else {
for (const path of candidates) {
try {
text = await readFile(path, "utf8");
break;
} catch (error) {
if (errorCode(error) !== "ENOENT") throw error;
}
}
}
if (text === null) return { status: "missing", connectEnabled: null };
try {
const value: unknown = JSON.parse(text);
if (!isRecord(value) || typeof value.connectEnabled !== "boolean") {
return { status: "invalid", connectEnabled: null };
}
return { status: "available", connectEnabled: value.connectEnabled };
} catch {
return { status: "invalid", connectEnabled: null };
}
}
+62
View File
@@ -0,0 +1,62 @@
import assert from "node:assert/strict";
import test from "node:test";
import { claim, createBriefRun, testBrief } from "../src/brief.ts";
test("testBrief rejects invalid definitions", () => {
assert.throws(() => testBrief({ behavior: " ", claims: { valid: claim("works") } }), /behavior must not be empty/);
assert.throws(() => testBrief({ behavior: "Works.", claims: {} }), /at least one claim/);
assert.throws(() => testBrief({ behavior: "Works.", claims: { blankMust: claim(" ") } }), /blankMust.*blank must/);
assert.throws(() => testBrief({ behavior: "Works.", claims: { blankNever: claim("works", { never: " " }) } }), /blankNever.*blank never/);
});
test("a run records true proofs and reports its facts", () => {
const recorded: { claimText: string; evidence: string; passed: boolean }[] = [];
const brief = testBrief({
behavior: "Two claims work.",
claims: {
first: claim("the first succeeds"),
second: claim("the second succeeds", { never: "silently disappear" }),
},
});
const run = createBriefRun(brief, (claimText, evidence, passed) => recorded.push({ claimText, evidence, passed }));
run.prove.first(true, "first observed");
run.prove.second(true, "second observed");
assert.deepEqual(run.facts(), [
{ key: "first", passed: true, evidence: "first observed" },
{ key: "second", passed: true, evidence: "second observed" },
]);
assert.doesNotThrow(() => run.assertAllProven());
assert.equal(recorded[0].claimText, "first: the first succeeds");
assert.equal(recorded[1].claimText, "second: the second succeeds — never: silently disappear");
});
test("a failed proof records before throwing", () => {
const recorded: { passed: boolean }[] = [];
const run = createBriefRun(testBrief({ behavior: "Failure is visible.", claims: { failure: claim("must pass") } }), (_claimText, _evidence, passed) => recorded.push({ passed }));
assert.throws(() => run.prove.failure(false, "observed failure"), /Claim failed: failure/);
assert.deepEqual(recorded, [{ passed: false }]);
});
test("blank proof evidence throws without recording", () => {
const recorded: string[] = [];
const run = createBriefRun(testBrief({ behavior: "Evidence is required.", claims: { evidenced: claim("has evidence") } }), (claimText) => recorded.push(claimText));
assert.throws(() => run.prove.evidenced(true, " "), /must not be blank/);
assert.deepEqual(recorded, []);
});
test("assertAllProven names only the missing claim", () => {
const run = createBriefRun(testBrief({
behavior: "Every claim is required.",
claims: { proven: claim("is proven"), missing: claim("is also proven") },
}), () => {});
run.prove.proven(true, "proven here");
assert.throws(
() => run.assertAllProven(),
/^Error: Brief claims left unproven: missing\. Every declared claim needs a prove\.<claim>\(\) call\.$/,
);
});
@@ -0,0 +1,46 @@
import assert from "node:assert/strict";
import test from "node:test";
import { eventually, sleep } from "../src/eventually.ts";
test("eventually polls until the default truthy condition passes", async () => {
let attempts = 0;
const value = await eventually(() => {
attempts += 1;
return attempts >= 3 ? "ready" : "";
}, { within: 100, intervalMs: 1 });
assert.equal(value, "ready");
assert.equal(attempts, 3);
});
test("eventually supports custom conditions and asynchronous probes", async () => {
let value = 0;
const result = await eventually(async () => {
await sleep(1);
value += 1;
return value;
}, { within: 100, intervalMs: 1, until: (candidate) => candidate === 2 });
assert.equal(result, 2);
});
test("eventually reports its label and last value on timeout", async () => {
await assert.rejects(
eventually(() => ({ ready: false }), {
within: 5,
intervalMs: 1,
label: "fake readiness",
until: (value) => value.ready,
}),
/Timed out waiting for fake readiness.*last value: \{"ready":false\}/,
);
});
test("eventually reports the last probe error on timeout", async () => {
await assert.rejects(
eventually(() => {
throw new Error("fake failure");
}, { within: 5, intervalMs: 1, label: "erroring probe" }),
/Timed out waiting for erroring probe.*last error: "fake failure"/,
);
});
+356
View File
@@ -0,0 +1,356 @@
import assert from "node:assert/strict";
import { createServer, request as httpRequest } from "node:http";
import test from "node:test";
import { daytonaLinkCommands, denLink, MAX_LINK_DAYTONA_COMMAND_LENGTH } from "../src/link.ts";
import type { Server } from "node:http";
import type { DaytonaExec } from "@openwork/hosts";
const LARGE_BODY = Buffer.alloc(192 * 1024, 97);
const ADMIN_TOKEN = "a".repeat(64);
function listen(server: Server): Promise<number> {
return new Promise((resolve, reject) => {
server.once("error", reject);
server.listen(0, "127.0.0.1", () => {
const address = server.address();
if (typeof address === "object" && address !== null) resolve(address.port);
else reject(new Error("Upstream test server did not expose a port."));
});
});
}
function close(server: Server): Promise<void> {
return new Promise((resolve, reject) => {
server.close((error) => error ? reject(error) : resolve());
server.closeAllConnections();
});
}
function timedFetch(url: string, timeoutMs = 5_000): Promise<Response> {
return fetch(url, { signal: AbortSignal.timeout(timeoutMs) });
}
function absoluteGet(proxyUrl: string, target: string): Promise<string> {
const proxy = new URL(proxyUrl);
return new Promise((resolve, reject) => {
const request = httpRequest({ hostname: proxy.hostname, port: proxy.port, path: target }, (response) => {
response.setEncoding("utf8");
let body = "";
response.on("data", (chunk: string) => body += chunk);
response.on("end", () => resolve(body));
});
request.on("error", reject);
request.end();
});
}
test("Daytona link commands upload the runner-side script before launching its temp path", () => {
const source = Buffer.alloc(32 * 1024, 97);
const commands = daytonaLinkCommands(source, "https://den.example.test", 3985, 3986, ADMIN_TOKEN);
assert(commands.cleanup.includes("pid=$(</tmp/openwork-den-link-server.pid)"));
assert(commands.cleanup.includes('kill "$pid"'));
assert(commands.cleanup.includes("rm -f /tmp/openwork-den-link-server.pid /tmp/openwork-den-link-server.mjs /tmp/openwork-den-link-server.mjs.b64"));
assert(!commands.cleanup.includes("pkill"));
assert.equal(commands.upload[0], ": > /tmp/openwork-den-link-server.mjs.b64");
const chunkPattern = /^printf %s ([A-Za-z0-9+/=]+) >> \/tmp\/openwork-den-link-server\.mjs\.b64$/;
const chunks = commands.upload.slice(1, -1).map((command) => {
const match = chunkPattern.exec(command);
assert(match);
assert(match[1].length <= 8 * 1024);
return match[1];
});
assert.equal(chunks.join(""), source.toString("base64"));
const finalize = commands.upload.at(-1);
assert(finalize?.includes("base64 -d /tmp/openwork-den-link-server.mjs.b64 > /tmp/openwork-den-link-server.mjs"));
assert(finalize?.includes("actual_bytes=$(wc -c < /tmp/openwork-den-link-server.mjs)"));
assert(finalize?.includes("rm -f /tmp/openwork-den-link-server.mjs.b64"));
assert(finalize?.includes(`test \"$actual_bytes\" -eq ${source.byteLength}`));
const commandLengths = [commands.cleanup, ...commands.upload, commands.detach]
.map((command) => ["exec", "desktop-sandbox", "--", `bash -lc '${command}'`].join(" ").length);
assert(Math.max(...commandLengths) <= MAX_LINK_DAYTONA_COMMAND_LENGTH);
assert(commands.detach.includes('"node", "/tmp/openwork-den-link-server.mjs"'));
assert(commands.detach.includes("pid_file.write(str(process.pid)"));
assert(commands.detach.includes('os.replace(temporary_pid, "/tmp/openwork-den-link-server.pid")'));
assert(commands.detach.includes(`env={**os.environ, "LINK_ADMIN_TOKEN": "${ADMIN_TOKEN}"}`));
const launch = commands.detach.split("\n").find((line) => line.startsWith("process = subprocess.Popen"));
assert(launch);
assert(!launch.slice(0, launch.indexOf("], stdin=")).includes(ADMIN_TOKEN));
assert(!commands.detach.includes("/workspace/evals"));
assert.throws(
() => daytonaLinkCommands(source, "https://den.example.test", 3985, 3986, "not-hex"),
/at least 32 lowercase hex characters/,
);
});
test("denLink separates a sandbox loopback client from public admin control and defaults to public previews", async () => {
const calls: string[][] = [];
const exec: DaytonaExec = async (args) => {
calls.push(args);
const previewPort = args[0] === "preview-url" ? args.at(-1) : undefined;
return {
stdout: previewPort === "3985"
? "https://data-preview.example.test\n"
: previewPort === "3986" ? "https://admin-preview.example.test\n" : "",
stderr: "",
code: 0,
};
};
const originalFetch = globalThis.fetch;
const fetched: Array<{ url: string; authorization: string | null }> = [];
globalThis.fetch = async (input, init) => {
fetched.push({ url: String(input), authorization: new Headers(init?.headers).get("authorization") });
return new Response(JSON.stringify({ ok: true, phase: "default", offline: false }), {
headers: { "content-type": "application/json" },
});
};
try {
{
await using link = await denLink(
{ apiUrl: "https://den.example.test/api/den", webUrl: "https://den.example.test" },
{ sandboxId: "desktop-sandbox", client: "sandbox-loopback", daytonaExec: exec },
);
assert.deepEqual(link.ref, {
apiUrl: "http://127.0.0.1:3985/api/den",
webUrl: "http://127.0.0.1:3985",
});
assert(calls.some((args) => args[0] === "exec" && args.at(-1)?.includes("http://127.0.0.1:3986/health")));
assert.deepEqual(
calls.filter((args) => args[0] === "preview-url").map((args) => args.at(-1)),
["3986"],
);
assert.equal(fetched.length, 1);
assert.equal(fetched[0]?.url, "https://admin-preview.example.test/health");
assert.match(fetched[0]?.authorization ?? "", /^Bearer [a-f0-9]{64}$/);
const healthCommand = calls.find((args) => args[0] === "exec" && args.at(-1)?.includes("curl -sf"))?.at(-1);
assert.match(healthCommand ?? "", /curl -sf -H "Authorization: Bearer [a-f0-9]{64}" http:\/\/127\.0\.0\.1:3986\/health/);
}
calls.length = 0;
fetched.length = 0;
await using publicLink = await denLink(
{ apiUrl: "https://den.example.test/api/den", webUrl: "https://den.example.test" },
{ sandboxId: "desktop-sandbox", daytonaExec: exec },
);
assert.deepEqual(publicLink.ref, {
apiUrl: "https://data-preview.example.test/api/den",
webUrl: "https://data-preview.example.test",
});
assert.deepEqual(
calls.filter((args) => args[0] === "preview-url").map((args) => args.at(-1)),
["3985", "3986"],
);
} finally {
globalThis.fetch = originalFetch;
}
});
test("denLink admin rejects missing and wrong bearer tokens without mutating state", async () => {
const upstream = createServer((_request, response) => response.end("ok"));
const port = await listen(upstream);
const originalFetch = globalThis.fetch;
let adminHealthUrl = "";
let authorization = "";
globalThis.fetch = async (input, init) => {
const url = String(input);
const header = new Headers(init?.headers).get("authorization");
if (url.endsWith("/health") && header !== null) {
adminHealthUrl = url;
authorization = header;
}
return originalFetch(input, init);
};
try {
await using link = await denLink({
apiUrl: `http://127.0.0.1:${port}/api/den`,
webUrl: `http://127.0.0.1:${port}`,
});
await link.admin.phase("protected");
assert.match(authorization, /^Bearer [a-f0-9]{64}$/);
const phaseUrl = adminHealthUrl.replace(/\/health$/, "/phase");
for (const headers of [
{ "content-type": "application/json" },
{ authorization: "Bearer " + "b".repeat(64), "content-type": "application/json" },
]) {
const denied = await originalFetch(phaseUrl, {
method: "POST",
headers,
body: JSON.stringify({ name: "attacker" }),
});
assert.equal(denied.status, 401);
assert.deepEqual(await denied.json(), { error: "Unauthorized" });
}
assert.equal((await link.admin.health()).phase, "protected");
} finally {
globalThis.fetch = originalFetch;
await close(upstream);
}
});
test("denLink shapes a local Den connection and records phases", { timeout: 25_000 }, async () => {
const upstream = createServer((request, response) => {
if (request.url === "/large") {
response.writeHead(200, { "content-length": LARGE_BODY.length, "content-type": "application/octet-stream" });
response.end(LARGE_BODY);
return;
}
if (request.url === "/stream") {
response.writeHead(200, { "content-type": "application/octet-stream" });
response.write(Buffer.alloc(16 * 1024, 98));
let writes = 0;
const timer = setInterval(() => {
if (writes === 9) {
clearInterval(timer);
response.end();
return;
}
writes += 1;
response.write(Buffer.alloc(16 * 1024, 98));
}, 200);
response.once("close", () => clearInterval(timer));
return;
}
response.writeHead(200, { "content-type": "application/json", "x-upstream": "yes" });
response.end(JSON.stringify({ ok: true, path: request.url }));
});
const port = await listen(upstream);
try {
await using link = await denLink({
apiUrl: `http://127.0.0.1:${port}/api/den`,
webUrl: `http://127.0.0.1:${port}`,
});
const passed = await timedFetch(`${link.ref.webUrl}/passthrough`);
assert.equal(passed.status, 200);
assert.equal(passed.headers.get("x-upstream"), "yes");
assert.deepEqual(await passed.json(), { ok: true, path: "/passthrough" });
let log = await link.admin.requests();
assert.deepEqual(
{ faulted: log.requests[0]?.faulted, phase: log.requests[0]?.phase },
{ faulted: false, phase: "default" },
);
await link.admin.rules([{ kind: "status", pathPrefix: "/status", statusCode: 503, times: 2, body: { error: "unavailable" } }]);
assert.equal((await timedFetch(`${link.ref.webUrl}/status`)).status, 503);
assert.equal((await timedFetch(`${link.ref.webUrl}/status`)).status, 503);
assert.equal((await timedFetch(`${link.ref.webUrl}/status`)).status, 200);
log = await link.admin.requests();
assert.deepEqual(log.requests.slice(-3).map(({ faulted, fault }) => ({ faulted, fault })), [
{ faulted: true, fault: "status" },
{ faulted: true, fault: "status" },
{ faulted: false, fault: undefined },
]);
await link.admin.rules([{ kind: "latency", pathPrefix: "/latency", delayMs: 300, jitterMs: 50 }]);
const latencyStarted = Date.now();
assert.equal((await timedFetch(`${link.ref.webUrl}/latency`)).status, 200);
const latencyElapsed = Date.now() - latencyStarted;
assert(latencyElapsed >= 250, `Expected at least 250ms latency, got ${latencyElapsed}ms.`);
assert(latencyElapsed <= 1_200, `Expected at most 1200ms latency, got ${latencyElapsed}ms.`);
await link.admin.rules([{ kind: "reset", pathPrefix: "/reset", everyNth: 2 }]);
assert.equal((await timedFetch(`${link.ref.webUrl}/reset`)).status, 200);
await assert.rejects(timedFetch(`${link.ref.webUrl}/reset`));
assert.equal((await timedFetch(`${link.ref.webUrl}/reset`)).status, 200);
await assert.rejects(timedFetch(`${link.ref.webUrl}/reset`));
await link.admin.phase("offline");
await link.admin.offline(600);
await assert.rejects(timedFetch(`${link.ref.webUrl}/offline`, 2_000));
log = await link.admin.requests();
assert((log.refusedConnections.offline ?? 0) >= 1);
await new Promise((resolve) => setTimeout(resolve, 800));
assert.equal((await timedFetch(`${link.ref.webUrl}/restored`)).status, 200);
assert.equal((await link.admin.health()).offline, false);
await link.admin.clear();
const streaming = await timedFetch(`${link.ref.webUrl}/stream`);
assert(streaming.body);
const reader = streaming.body.getReader();
const firstChunk = await reader.read();
assert.equal(firstChunk.done, false);
await link.admin.offline(600);
await assert.rejects(reader.read());
await new Promise((resolve) => setTimeout(resolve, 700));
await link.admin.bandwidth(64 * 1024);
const cappedStarted = Date.now();
const capped = await timedFetch(`${link.ref.webUrl}/large`, 8_000);
const cappedBody = Buffer.from(await capped.arrayBuffer());
const cappedElapsed = Date.now() - cappedStarted;
assert(cappedElapsed >= 2_500, `Expected capped transfer to take at least 2500ms, got ${cappedElapsed}ms.`);
assert.deepEqual(cappedBody, LARGE_BODY);
assert.equal((await link.admin.requests()).requests.at(-1)?.fault, "bandwidth");
await link.admin.bandwidth(null);
const fastStarted = Date.now();
const fast = await timedFetch(`${link.ref.webUrl}/large`);
assert.deepEqual(Buffer.from(await fast.arrayBuffer()), LARGE_BODY);
assert(Date.now() - fastStarted < 1_000);
await link.admin.phase("b");
assert.equal((await timedFetch(`${link.ref.webUrl}/phase-b`)).status, 200);
log = await link.admin.requests();
assert.equal(log.requests.at(-1)?.phase, "b");
await link.admin.phase("vpn", "vpn-flaky-emulated");
const vpnStarted = Date.now();
assert.equal((await timedFetch(`${link.ref.webUrl}/vpn-success-1`)).status, 200);
const vpnDelay = Date.now() - vpnStarted;
assert(vpnDelay >= 300, `Expected VPN emulation latency of at least 300ms, got ${vpnDelay}ms.`);
assert(vpnDelay < 1_500, `Expected bounded VPN emulation latency, got ${vpnDelay}ms.`);
assert.equal((await timedFetch(`${link.ref.webUrl}/vpn-success-2`)).status, 200);
await assert.rejects(timedFetch(`${link.ref.webUrl}/vpn-reset`));
const stats = await link.admin.stats();
assert.equal(stats.phase, "vpn");
assert.equal(stats.profile, "vpn-flaky-emulated");
assert(stats.faults >= 1);
log = await link.admin.requests();
assert.deepEqual(log.requests.slice(-3).map(({ fault, profile }) => ({ fault, profile })), [
{ fault: "latency", profile: "vpn-flaky-emulated" },
{ fault: "latency", profile: "vpn-flaky-emulated" },
{ fault: "reset", profile: "vpn-flaky-emulated" },
]);
await link.admin.phase("baseline", "baseline");
assert.equal((await timedFetch(`${link.ref.webUrl}/baseline-restored`)).status, 200);
const baselineEntry = (await link.admin.requests()).requests.at(-1);
assert.deepEqual(
baselineEntry && { path: baselineEntry.path, faulted: baselineEntry.faulted, phase: baselineEntry.phase, profile: baselineEntry.profile },
{ path: "/baseline-restored", faulted: false, phase: "baseline", profile: "baseline" },
);
await link.admin.rules([{ kind: "status", statusCode: 500, times: 10 }]);
await link.admin.clear();
assert.equal((await timedFetch(`${link.ref.webUrl}/cleared`)).status, 200);
assert.equal((await link.admin.health()).offline, false);
} finally {
await close(upstream);
}
});
test("denLink pins absolute-form request targets to its upstream", async () => {
let attackerRequests = 0;
let upstreamRequestUrl: string | undefined;
const upstream = createServer((request, response) => {
upstreamRequestUrl = request.url;
response.end("upstream");
});
const attacker = createServer((_request, response) => {
attackerRequests += 1;
response.end("attacker");
});
const [upstreamPort, attackerPort] = await Promise.all([listen(upstream), listen(attacker)]);
try {
await using link = await denLink({
apiUrl: `http://127.0.0.1:${upstreamPort}/api/den`,
webUrl: `http://127.0.0.1:${upstreamPort}`,
});
assert.equal(
await absoluteGet(link.ref.webUrl, `http://127.0.0.1:${attackerPort}/steered?x=1`),
"upstream",
);
assert.equal(upstreamRequestUrl, "/steered?x=1");
assert.equal(attackerRequests, 0);
} finally {
await Promise.all([close(upstream), close(attacker)]);
}
});
@@ -0,0 +1,27 @@
import assert from "node:assert/strict";
import test from "node:test";
import type { Place } from "@openwork/env";
import { selfHostServer } from "../src/self-host.ts";
test("selfHostServer skips Daytona placement", async () => {
const place: Place = {
kind: "daytona",
host() {
throw new Error("host must not be called");
},
async db() {
throw new Error("db must not be called");
},
async exposeMock() {
throw new Error("exposeMock must not be called");
},
denBase() {
throw new Error("denBase must not be called");
},
};
await assert.rejects(
selfHostServer({ place, name: "Test", slug: "test", ownerEmails: ["owner@example.test"] }),
(error: unknown) => error instanceof Error && error.name === "SkipError" && error.message.includes("OPENWORK_EVAL_DAYTONA"),
);
});
@@ -0,0 +1,97 @@
import assert from "node:assert/strict";
import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import test from "node:test";
import { electronProfilePaths } from "@openwork/hosts";
import { readConnectStateFile } from "../src/state.ts";
import type { CdpClient, Surface } from "@openwork/cdp";
const MISSING = "__OPENWORK_TESTKIT_MISSING__";
function surface(hostKind: string, profileDir?: string, sandboxId?: string): Surface {
const client: CdpClient = {
async send() {
throw new Error("CDP must not be called.");
},
close() {},
};
return {
handle: { name: "desktop", kind: "electron", hostKind, cdpUrl: "http://127.0.0.1:1", profileDir, sandboxId },
client,
};
}
test("readConnectStateFile reads Daytona candidates in order", async () => {
const calls: Array<{ sandbox: string; script: string }> = [];
const app = surface("daytona", "/workspace/profiles/desktop", "sandbox-1");
const result = await readConnectStateFile(app, {
exec: async (sandbox, script) => {
calls.push({ sandbox, script });
return calls.length === 1 ? MISSING : '{"connectEnabled":true}';
},
});
assert.deepEqual(result, { status: "available", connectEnabled: true });
assert.deepEqual(calls.map(({ sandbox }) => sandbox), ["sandbox-1", "sandbox-1"]);
assert(calls[0]?.script.includes("/workspace/profiles/desktop/electron-userdata/openwork-dev-data/xdg/config/openwork/connect-state.json"));
assert(calls[1]?.script.includes("/workspace/profiles/desktop/xdg-config/openwork/connect-state.json"));
assert(calls.every(({ script }) => !script.includes("'")));
});
test("readConnectStateFile reports non-JSON Daytona content as invalid", async () => {
const result = await readConnectStateFile(surface("daytona", "/workspace/profile", "sandbox"), { exec: async () => "not-json" });
assert.deepEqual(result, { status: "invalid", connectEnabled: null });
});
test("readConnectStateFile reports missing when every Daytona candidate is absent", async () => {
let calls = 0;
const result = await readConnectStateFile(surface("daytona", "/workspace/profile", "sandbox"), {
exec: async () => {
calls += 1;
return MISSING;
},
});
assert.deepEqual(result, { status: "missing", connectEnabled: null });
assert.equal(calls, 3);
});
test("readConnectStateFile requires a boolean connectEnabled", async () => {
const result = await readConnectStateFile(surface("daytona", "/workspace/profile", "sandbox"), { exec: async () => "{}" });
assert.deepEqual(result, { status: "invalid", connectEnabled: null });
});
test("readConnectStateFile rejects unsupported host kinds", async () => {
await assert.rejects(readConnectStateFile(surface("attached", "/tmp/profile")), /supports local and daytona/);
});
test("readConnectStateFile requires a Daytona sandbox ID", async () => {
await assert.rejects(readConnectStateFile(surface("daytona", "/workspace/profile")), /daytona app did not expose its sandbox ID/);
});
test("readConnectStateFile rejects unsafe Daytona profile paths without executing", async () => {
let called = false;
await assert.rejects(
readConnectStateFile(surface("daytona", "/workspace/unsafe profile", "sandbox"), {
exec: async () => {
called = true;
return MISSING;
},
}),
/Unsafe connect-state path.*unsafe profile/,
);
assert.equal(called, false);
});
test("readConnectStateFile preserves local profile reads", async () => {
const root = await mkdtemp(join(tmpdir(), "openwork-state-test-"));
try {
const paths = electronProfilePaths(root);
const statePath = join(paths.configHome, "openwork", "connect-state.json");
await mkdir(dirname(statePath), { recursive: true });
await writeFile(statePath, '{"connectEnabled":false}', "utf8");
assert.deepEqual(await readConnectStateFile(surface("local", root)), { status: "available", connectEnabled: false });
} finally {
await rm(root, { recursive: true, force: true });
}
});
+109
View File
@@ -0,0 +1,109 @@
import assert from "node:assert/strict";
import test from "node:test";
import {
checkNeeds,
deriveMockEnv,
ephemeralDatabaseName,
needs,
resolvePlace,
SkipError,
trustedOrigins,
} from "@openwork/env";
test("resolvePlace selects local unless OPENWORK_EVAL_DAYTONA is exactly 1", () => {
const local = resolvePlace({});
const falseyDaytona = resolvePlace({ OPENWORK_EVAL_DAYTONA: "0" });
const daytona = resolvePlace({ OPENWORK_EVAL_DAYTONA: "1", OPENWORK_EVAL_REF: "feature-ref" });
assert.equal(local.kind, "local");
assert.equal(falseyDaytona.kind, "local");
assert.equal(daytona.kind, "daytona");
assert.deepEqual(daytona.denBase(), { kind: "daytona", ref: "feature-ref" });
});
test("needs accepts a tool-capable model and provider key", () => {
assert.doesNotThrow(() => checkNeeds(
{ model: "tool-capable", env: ["EXTRA_REQUIRED"] },
{
OPENWORK_EVAL_MODEL: "openai/gpt-5",
OPENAI_API_KEY: "test-key",
EXTRA_REQUIRED: "1",
},
));
});
test("needs throws a named SkipError for every unsatisfied resource", () => {
assert.throws(
() => checkNeeds({ model: "tool-capable", env: ["EXTRA_REQUIRED"], optIn: ["EXACT_OPT_IN"], daytona: true }, {}),
(error) => {
assert(error instanceof SkipError);
assert.match(error.message, /^needs: /);
assert.match(error.message, /set EXTRA_REQUIRED/);
assert.match(error.message, /set EXACT_OPT_IN=1/);
assert.match(error.message, /set OPENWORK_EVAL_MODEL/);
assert.match(error.message, /set OPENAI_API_KEY or ANTHROPIC_API_KEY/);
assert.match(error.message, /set OPENWORK_EVAL_DAYTONA=1/);
return true;
},
);
});
test("needs only accepts opt-in gates set exactly to 1", () => {
assert.throws(() => checkNeeds({ optIn: ["EXACT_OPT_IN"] }, { EXACT_OPT_IN: "true" }), SkipError);
assert.doesNotThrow(() => checkNeeds({ optIn: ["EXACT_OPT_IN"] }, { EXACT_OPT_IN: "1" }));
});
test("needs reports an unavailable command", () => {
const command = "openwork-impossible-command-for-testkit-test";
assert.throws(
() => checkNeeds({ commands: [command] }, {}),
(error) => error instanceof SkipError && error.message.includes(`install ${command}`),
);
});
test("needs rejects a local-only test on Daytona or an attached Den", () => {
assert.doesNotThrow(() => checkNeeds({ placement: "local" }, {}));
assert.throws(() => checkNeeds({ placement: "local" }, { OPENWORK_EVAL_DAYTONA: "1" }), SkipError);
assert.throws(
() => checkNeeds({ placement: "local" }, { OPENWORK_EVAL_DEN_API_URL: "https://den.example.test" }),
SkipError,
);
});
test("needs reads process.env at the call site", () => {
const name = "OPENWORK_TESTKIT_UNIT_RESOURCE";
const previous = process.env[name];
try {
delete process.env[name];
assert.throws(() => needs({ env: [name] }), SkipError);
process.env[name] = "available";
assert.deepEqual(needs({ env: [name] }), {});
} finally {
if (previous === undefined) delete process.env[name];
else process.env[name] = previous;
}
});
test("mcp mock environment is derived from the resource name and public URLs", () => {
assert.deepEqual(
deriveMockEnv("acme tickets", "https://mock.example.test", "https://mock.example.test/mcp"),
{
OPENWORK_EVAL_MOCK_ACME_TICKETS_URL: "https://mock.example.test",
OPENWORK_EVAL_MOCK_ACME_TICKETS_MCP_URL: "https://mock.example.test/mcp",
},
);
});
test("trusted origins contain both Den ports in localhost and loopback forms", () => {
assert.deepEqual(trustedOrigins(8788, 3005), [
"http://localhost:8788",
"http://127.0.0.1:8788",
"http://localhost:3005",
"http://127.0.0.1:3005",
]);
});
test("ephemeral database names are valid and unique", () => {
const names = new Set(Array.from({ length: 100 }, () => ephemeralDatabaseName()));
assert.equal(names.size, 100);
for (const name of names) assert.match(name, /^[a-z][a-z0-9_]{0,62}$/);
});