Diffinery

codician/diffinerypublic

Open-source, agent-first GitHub and GitHub Actions alternative that runs on your own Cloudflare account: git hosting, pull requests, code review and drop-in GitHub Actions YAML on Workers, Durable Objects, R2 and Containers.

E2E: give test servers ports nothing else can take (fixes "bind(): Address already in use")

Every e2e file picked ports by listening on port 0 and closing the socket, then passing
the number to wrangler dev. Until wrangler bound it, anything binding port 0 (workerd in
another wrangler dev or `wrangler d1 execute`, a docs server, an outgoing connection)
could be handed the same port, and the Workers runtime died at start. Seen on
claude/ci-status-in-claude (OAuth) and claude/indexnow-fallback (real histories).

test/e2e/ports.mjs replaces the 18 copies (and the docs screenshot script's): ports come
from below the kernel's ephemeral range, which port 0 binds and outgoing connections
never use, each reserved with a lock file so files running side by side never share one.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M5tHXfgBQaLEPM9iUPrp8n
Claude authored signed1 parent c101f89commit cb34324764990a819179e0255d0e7275670a8ea3Browse files
22 files changed+147−184
Files (22)
modifiedapps/diffinery/scripts/docs-screenshots.mjs+2−8View file
@@ -13,19 +13,13 @@
1313 import { tmpdir } from "node:os";
1414 import { join, dirname, resolve } from "node:path";
1515 import { fileURLToPath } from "node:url";
16-import { createServer } from "node:net";
1716 import { chromium } from "playwright";
17+import { freePort } from "../test/e2e/ports.mjs";
1818
1919 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "..");
2020 const OUT = join(APP, "docs/images");
2121 const PUBLIC = "https://diffinery.com";
22-const port = await new Promise((res) => {
23- const srv = createServer();
24- srv.listen(0, "127.0.0.1", () => {
25- const { port } = srv.address();
26- srv.close(() => res(port));
27- });
28-});
22+const port = await freePort();
2923 // The browser talks to the Worker here; the pages themselves say diffinery.com.
3024 const ORIGIN = `http://localhost:${port}`;
3125 const only = process.argv.slice(2);
modifiedapps/diffinery/test/e2e/accounts.test.mjs+1−10View file
@@ -13,10 +13,10 @@
1313 import { tmpdir } from "node:os";
1414 import { join, dirname, resolve } from "node:path";
1515 import { fileURLToPath } from "node:url";
16-import { createServer } from "node:net";
1716 import { test, before, after } from "node:test";
1817 import assert from "node:assert/strict";
1918 import { migratedState } from "./d1-state.mjs";
19+import { freePort } from "./ports.mjs";
2020
2121 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2222 const work = mkdtempSync(join(tmpdir(), "diffinery-accounts-"));
@@ -30,15 +30,6 @@
3030 const T = { sully: tok("sully"), alice: tok("alice"), alicebot: tok("alicebot"), bob: tok("bob"), carl: tok("carl"), erin: tok("erin"), dan: tok("dan") };
3131 const S = { sully: sess("sully"), sullyOld: sess("sullyold"), alice: sess("alice"), aliceOther: sess("aliceother"), bob: sess("bob"), carl: sess("carl"), erin: sess("erin"), dan: sess("dan") };
3232
33-const freePort = () =>
34- new Promise((res) => {
35- const s = createServer();
36- s.listen(0, "127.0.0.1", () => {
37- const { port } = s.address();
38- s.close(() => res(port));
39- });
40- });
41-
4233 const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
4334 async function until(what, fn, timeoutMs = 120_000) {
4435 const end = Date.now() + timeoutMs;
modifiedapps/diffinery/test/e2e/agent-setup.test.mjs+1−9View file
@@ -18,10 +18,10 @@
1818 import { tmpdir } from "node:os";
1919 import { join, dirname, resolve } from "node:path";
2020 import { fileURLToPath } from "node:url";
21-import { createServer } from "node:net";
2221 import { test, before, after } from "node:test";
2322 import assert from "node:assert/strict";
2423 import { migratedState } from "./d1-state.mjs";
24+import { freePort } from "./ports.mjs";
2525
2626 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2727 const work = mkdtempSync(join(tmpdir(), "diffinery-agent-setup-"));
@@ -35,14 +35,6 @@
3535 const T = { ada: tok("ada"), bob: tok("bob"), wes: tok("wes") };
3636 const S = { ada: `ada-session-${randomBytes(12).toString("hex")}`, bob: `bob-session-${randomBytes(12).toString("hex")}`, wes: `wes-session-${randomBytes(12).toString("hex")}` };
3737
38-const freePort = () =>
39- new Promise((res) => {
40- const s = createServer();
41- s.listen(0, "127.0.0.1", () => {
42- const { port } = s.address();
43- s.close(() => res(port));
44- });
45- });
4638 const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
4739 async function until(what, fn, timeoutMs = 120_000) {
4840 const end = Date.now() + timeoutMs;
modifiedapps/diffinery/test/e2e/agentic.test.mjs+1−10View file
@@ -12,10 +12,10 @@
1212 import { randomBytes } from "node:crypto";
1313 import { join, dirname, resolve } from "node:path";
1414 import { fileURLToPath } from "node:url";
15-import { createServer } from "node:net";
1615 import { test, before, after } from "node:test";
1716 import assert from "node:assert/strict";
1817 import { migratedState } from "./d1-state.mjs";
18+import { freePort } from "./ports.mjs";
1919
2020 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2121 const work = mkdtempSync(join(tmpdir(), "diffinery-agentic-e2e-"));
@@ -24,15 +24,6 @@
2424 let devLog = "";
2525 let token;
2626
27-const freePort = () =>
28- new Promise((res) => {
29- const s = createServer();
30- s.listen(0, "127.0.0.1", () => {
31- const { port } = s.address();
32- s.close(() => res(port));
33- });
34- });
35-
3627 async function api(method, path, body, tok = token) {
3728 const res = await fetch(`${base}/api/v3${path}`, {
3829 method,
modifiedapps/diffinery/test/e2e/agents-harness.mjs+1−10View file
@@ -8,11 +8,11 @@
88 import { createRequire } from "node:module";
99 import { join, dirname, resolve } from "node:path";
1010 import { fileURLToPath } from "node:url";
11-import { createServer as netServer } from "node:net";
1211 import { createServer as httpServer } from "node:http";
1312 import { before, after } from "node:test";
1413 import assert from "node:assert/strict";
1514 import { migratedState } from "./d1-state.mjs";
15+import { freePort } from "./ports.mjs";
1616
1717 export const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
1818 export const AGENT = resolve(APP, "../../containers/runner/dist/agent.mjs");
@@ -37,15 +37,6 @@
3737 export let token;
3838 export const modelRequests = [];
3939
40-export const freePort = () =>
41- new Promise((res) => {
42- const s = netServer();
43- s.listen(0, "127.0.0.1", () => {
44- const { port } = s.address();
45- s.close(() => res(port));
46- });
47- });
48-
4940 export async function api(method, path, body, tok = token) {
5041 const res = await fetch(`${base}/api/v3${path}`, {
5142 method,
modifiedapps/diffinery/test/e2e/e2e.test.mjs+1−10View file
@@ -14,12 +14,12 @@
1414 import { createHash, randomBytes } from "node:crypto";
1515 import { join, dirname, resolve } from "node:path";
1616 import { fileURLToPath } from "node:url";
17-import { createServer } from "node:net";
1817 import { crc32, deflateSync } from "node:zlib";
1918 import { test, describe, before, after } from "node:test";
2019 import assert from "node:assert/strict";
2120 import { fakeGitHub, lfsObject } from "./fake-github.mjs";
2221 import { migratedState } from "./d1-state.mjs";
22+import { freePort } from "./ports.mjs";
2323
2424 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2525 const AGENT = resolve(APP, "../../containers/runner/dist/agent.mjs");
@@ -34,15 +34,6 @@
3434 let token;
3535 let agentToken;
3636
37-const freePort = () =>
38- new Promise((res) => {
39- const s = createServer();
40- s.listen(0, "127.0.0.1", () => {
41- const { port } = s.address();
42- s.close(() => res(port));
43- });
44- });
45-
4637 async function api(method, path, body, tok = token) {
4738 const send = () =>
4839 fetch(`${base}/api/v3${path}`, {
modifiedapps/diffinery/test/e2e/early-access.test.mjs+1−9View file
@@ -16,24 +16,16 @@
1616 import { tmpdir } from "node:os";
1717 import { join, dirname, resolve } from "node:path";
1818 import { fileURLToPath } from "node:url";
19-import { createServer } from "node:net";
2019 import { request as httpRequest } from "node:http";
2120 import { test, after } from "node:test";
2221 import assert from "node:assert/strict";
2322 import { migratedState } from "./d1-state.mjs";
23+import { freePort } from "./ports.mjs";
2424
2525 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2626 const work = mkdtempSync(join(tmpdir(), "diffinery-early-access-e2e-"));
2727 const running = [];
2828
29-const freePort = () =>
30- new Promise((res) => {
31- const s = createServer();
32- s.listen(0, "127.0.0.1", () => {
33- const { port } = s.address();
34- s.close(() => res(port));
35- });
36- });
3729 const hash = (s) => createHash("sha256").update(s).digest("hex");
3830 const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
3931
modifiedapps/diffinery/test/e2e/editor-smoke.mjs+1−10View file
@@ -14,12 +14,12 @@
1414 import { spawn, execFileSync } from "node:child_process";
1515 import { createHash, randomBytes } from "node:crypto";
1616 import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, chmodSync } from "node:fs";
17-import { createServer } from "node:net";
1817 import { tmpdir } from "node:os";
1918 import { join, dirname, resolve } from "node:path";
2019 import { fileURLToPath } from "node:url";
2120 import assert from "node:assert/strict";
2221 import { chromium, _electron } from "playwright";
22+import { freePort } from "./ports.mjs";
2323
2424 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2525 const EDITOR = process.env.EDITOR_BIN;
@@ -35,14 +35,6 @@
3535 const CHARLES_TOKEN = `dfy_${randomBytes(24).toString("hex")}`;
3636 let devLog = "";
3737
38-const freePort = () =>
39- new Promise((res) => {
40- const s = createServer();
41- s.listen(0, "127.0.0.1", () => {
42- const { port } = s.address();
43- s.close(() => res(port));
44- });
45- });
4638 async function until(what, fn, timeoutMs = 60_000) {
4739 const end = Date.now() + timeoutMs;
4840 while (Date.now() < end) {
@@ -322,7 +314,6 @@
322314 assert.ok(grants.length === 1 && grants[0].revoked_at, "the connection is revoked");
323315 console.log("signed out: credential removed, connection revoked");
324316
325-
326317 await app.close();
327318 cleanup();
328319 if (process.env.KEEP !== "1") rmSync(work, { recursive: true, force: true });
modifiedapps/diffinery/test/e2e/email.test.mjs+1−10View file
@@ -17,11 +17,11 @@
1717 import { createHmac, randomBytes } from "node:crypto";
1818 import { join, dirname, resolve } from "node:path";
1919 import { fileURLToPath } from "node:url";
20-import { createServer } from "node:net";
2120 import { test, before, after } from "node:test";
2221 import assert from "node:assert/strict";
2322 import { chromium } from "playwright";
2423 import { migratedState } from "./d1-state.mjs";
24+import { freePort } from "./ports.mjs";
2525
2626 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2727 const AGENT = resolve(APP, "../../containers/runner/dist/agent.mjs");
@@ -33,15 +33,6 @@
3333 let me;
3434 const eventsSecret = randomBytes(24).toString("hex");
3535
36-const freePort = () =>
37- new Promise((res) => {
38- const s = createServer();
39- s.listen(0, "127.0.0.1", () => {
40- const { port } = s.address();
41- s.close(() => res(port));
42- });
43- });
44-
4536 async function api(method, path, body, tok = token) {
4637 const res = await fetch(`${base}/api/v3${path}`, {
4738 method,
modifiedapps/diffinery/test/e2e/graphql.test.mjs+1−10View file
@@ -12,10 +12,10 @@
1212 import { tmpdir } from "node:os";
1313 import { join, dirname, resolve } from "node:path";
1414 import { fileURLToPath } from "node:url";
15-import { createServer } from "node:net";
1615 import { test, before, after } from "node:test";
1716 import assert from "node:assert/strict";
1817 import { migratedState } from "./d1-state.mjs";
18+import { freePort } from "./ports.mjs";
1919
2020 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2121 const work = mkdtempSync(join(tmpdir(), "diffinery-graphql-e2e-"));
@@ -23,15 +23,6 @@
2323 let base;
2424 let log = "";
2525
26-const freePort = () =>
27- new Promise((res) => {
28- const s = createServer();
29- s.listen(0, "127.0.0.1", () => {
30- const { port } = s.address();
31- s.close(() => res(port));
32- });
33- });
34-
3526 const hash = (s) => createHash("sha256").update(s).digest("hex");
3627 const T = { ann: `dfy_ann_${randomBytes(12).toString("hex")}`, annRead: `dfy_anr_${randomBytes(12).toString("hex")}`, bob: `dfy_bob_${randomBytes(12).toString("hex")}` };
3728
modifiedapps/diffinery/test/e2e/jetbrains-smoke.mjs+1−9View file
@@ -16,12 +16,12 @@
1616 import { spawn, execFileSync } from "node:child_process";
1717 import { createHash, randomBytes } from "node:crypto";
1818 import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, chmodSync, copyFileSync } from "node:fs";
19-import { createServer } from "node:net";
2019 import { tmpdir } from "node:os";
2120 import { join, dirname, resolve } from "node:path";
2221 import { fileURLToPath } from "node:url";
2322 import assert from "node:assert/strict";
2423 import { chromium } from "playwright";
24+import { freePort } from "./ports.mjs";
2525
2626 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2727 const IDE = process.env.IDE_HOME;
@@ -38,14 +38,6 @@
3838 const CHARLES_TOKEN = `dfy_${randomBytes(24).toString("hex")}`;
3939 let devLog = "";
4040
41-const freePort = () =>
42- new Promise((res) => {
43- const s = createServer();
44- s.listen(0, "127.0.0.1", () => {
45- const { port } = s.address();
46- s.close(() => res(port));
47- });
48- });
4941 async function until(what, fn, timeoutMs = 60_000) {
5042 const end = Date.now() + timeoutMs;
5143 let last;
modifiedapps/diffinery/test/e2e/moderation.test.mjs+1−9View file
@@ -14,10 +14,10 @@
1414 import { tmpdir } from "node:os";
1515 import { join, dirname, resolve } from "node:path";
1616 import { fileURLToPath } from "node:url";
17-import { createServer } from "node:net";
1817 import { test, before, after } from "node:test";
1918 import assert from "node:assert/strict";
2019 import { migratedState } from "./d1-state.mjs";
20+import { freePort } from "./ports.mjs";
2121
2222 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2323 const work = mkdtempSync(join(tmpdir(), "diffinery-moderation-"));
@@ -30,14 +30,6 @@
3030 const T = { olive: tok("olive"), sully: tok("sully"), rita: tok("rita"), mal: tok("mal"), sid: tok("sid"), sam: tok("sam") };
3131 const S = { olive: `olive-${randomBytes(12).toString("hex")}`, sully: `sully-${randomBytes(12).toString("hex")}`, rita: `rita-${randomBytes(12).toString("hex")}`, sid: `sid-${randomBytes(12).toString("hex")}` };
3232
33-const freePort = () =>
34- new Promise((res) => {
35- const s = createServer();
36- s.listen(0, "127.0.0.1", () => {
37- const { port } = s.address();
38- s.close(() => res(port));
39- });
40- });
4133 const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
4234
4335 /** Call the REST API as a token, a session cookie (`{ cookie }`) or anonymously (null). */
modifiedapps/diffinery/test/e2e/oauth.test.mjs+1−9View file
@@ -11,7 +11,6 @@
1111 import { createHash, randomBytes } from "node:crypto";
1212 import { mkdtempSync, rmSync } from "node:fs";
1313 import { createServer as createHttpServer } from "node:http";
14-import { createServer } from "node:net";
1514 import { tmpdir } from "node:os";
1615 import { join, dirname, resolve } from "node:path";
1716 import { fileURLToPath } from "node:url";
@@ -19,6 +18,7 @@
1918 import assert from "node:assert/strict";
2019 import { chromium } from "playwright";
2120 import { migratedState } from "./d1-state.mjs";
21+import { freePort } from "./ports.mjs";
2222
2323 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2424 const work = mkdtempSync(join(tmpdir(), "diffinery-oauth-"));
@@ -34,14 +34,6 @@
3434 const hash = (s) => createHash("sha256").update(s).digest("hex");
3535 const b64url = (b) => Buffer.from(b).toString("base64url");
3636
37-const freePort = () =>
38- new Promise((res) => {
39- const s = createServer();
40- s.listen(0, "127.0.0.1", () => {
41- const { port } = s.address();
42- s.close(() => res(port));
43- });
44- });
4537 const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
4638 async function until(what, fn, timeoutMs = 60_000) {
4739 const end = Date.now() + timeoutMs;
modifiedapps/diffinery/test/e2e/passkeys.test.mjs+1−10View file
@@ -17,11 +17,11 @@
1717 import { tmpdir } from "node:os";
1818 import { join, dirname, resolve } from "node:path";
1919 import { fileURLToPath } from "node:url";
20-import { createServer } from "node:net";
2120 import { test, before, after } from "node:test";
2221 import assert from "node:assert/strict";
2322 import { chromium } from "playwright";
2423 import { migratedState } from "./d1-state.mjs";
24+import { freePort } from "./ports.mjs";
2525
2626 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2727 const work = mkdtempSync(join(tmpdir(), "diffinery-passkeys-"));
@@ -42,15 +42,6 @@
4242 /** The proof only the invitation email carries (src/auth/invite-proof.ts). */
4343 const proofFor = (token) => createHmac("sha256", `diffinery-invite-proof-v1:${MASTER_KEY}`).update(hash(token)).digest("base64url");
4444
45-const freePort = () =>
46- new Promise((res) => {
47- const s = createServer();
48- s.listen(0, "127.0.0.1", () => {
49- const { port } = s.address();
50- s.close(() => res(port));
51- });
52- });
53-
5445 const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
5546 async function until(what, fn, timeoutMs = 60_000) {
5647 const end = Date.now() + timeoutMs;
addedapps/diffinery/test/e2e/ports.mjs+125−0View file
@@ -1,0 +1,125 @@
1+// Ports for the servers end-to-end tests start (`wrangler dev` and its inspector, the sandbox pool, ...).
2+//
3+// Asking the kernel for a free port (listen on 0, close, hand the number on) races: until the server
4+// binds it, the port is free again, and anything that binds port 0 meanwhile can be given the same
5+// number: workerd's own sockets in another `wrangler dev` or `wrangler d1 execute`, a docs server, an
6+// outgoing connection. Then wrangler dies with "bind(): Address already in use". So ports here come
7+// from below the kernel's ephemeral range, which port 0 binds and outgoing connections never use, and
8+// each is reserved with a lock file naming this process, so test files running side by side
9+// (--test-concurrency) never pick the same one. A process keeps its ports until it exits; a lock left
10+// by a process that's gone is taken over.
11+import { linkSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
12+import { createServer } from "node:net";
13+import { tmpdir } from "node:os";
14+import { join } from "node:path";
15+
16+const LOCKS = join(tmpdir(), "diffinery-e2e-ports");
17+const [FIRST, LAST] = range();
18+const held = new Set();
19+let next = FIRST + Math.floor(Math.random() * (LAST - FIRST + 1));
20+
21+process.on("exit", () => {
22+ for (const port of held) {
23+ try {
24+ unlinkSync(join(LOCKS, String(port)));
25+ } catch {}
26+ }
27+});
28+
29+/** A port on 127.0.0.1 that's free now and that no other caller, in this process or another, will be given. */
30+export async function freePort() {
31+ mkdirSync(LOCKS, { recursive: true });
32+ for (let tried = 0; tried <= LAST - FIRST; tried++) {
33+ const port = next;
34+ next = next === LAST ? FIRST : next + 1;
35+ if (held.has(port) || !reserve(port)) continue;
36+ if (await bindable(port)) {
37+ held.add(port);
38+ return port;
39+ }
40+ // Something outside the tests is listening there; leave the port to it.
41+ unlinkSync(join(LOCKS, String(port)));
42+ }
43+ throw new Error(`no free port left in ${FIRST}-${LAST}`);
44+}
45+
46+/** Ports from 20000 up to the kernel's ephemeral range (32768 to 60999 on Linux by default; macOS's starts at 49152). */
47+function range() {
48+ let [low, high] = [32768, 60999];
49+ try {
50+ [low, high] = readFileSync("/proc/sys/net/ipv4/ip_local_port_range", "utf8").trim().split(/\s+/).map(Number);
51+ } catch {}
52+ if (low >= 21000) return [20000, low - 1];
53+ // An ephemeral range starting this low leaves too few ports under it; use the ports above it.
54+ if (high <= 64000) return [high + 1, 65535];
55+ throw new Error(`the ephemeral port range (${low}-${high}) leaves no room for test servers`);
56+}
57+
58+/** Takes the lock file for `port`. It's written whole under a name of its own, then linked into place, so it never exists half written. */
59+function reserve(port) {
60+ const file = join(LOCKS, String(port));
61+ const mine = `${file}.${process.pid}`;
62+ writeFileSync(mine, String(process.pid));
63+ try {
64+ for (let attempt = 0; attempt < 2; attempt++) {
65+ try {
66+ linkSync(mine, file);
67+ return true;
68+ } catch (e) {
69+ if (e.code !== "EEXIST") throw e;
70+ }
71+ if (!takeOver(file)) return false;
72+ }
73+ return false;
74+ } finally {
75+ unlinkSync(mine);
76+ }
77+}
78+
79+/**
80+ * Moves a lock whose process is gone (killed before it could clean up) out of the way. It's renamed
81+ * before it's read again, so of two processes taking over the same lock only one moves it, and a live
82+ * lock moved by mistake goes back.
83+ */
84+function takeOver(file) {
85+ if (alive(pidIn(file))) return false;
86+ const moved = `${file}.stale-${process.pid}`;
87+ try {
88+ renameSync(file, moved);
89+ } catch {
90+ return false;
91+ }
92+ const dead = !alive(pidIn(moved));
93+ if (!dead) {
94+ try {
95+ linkSync(moved, file);
96+ } catch {}
97+ }
98+ unlinkSync(moved);
99+ return dead;
100+}
101+
102+function pidIn(file) {
103+ try {
104+ return Number(readFileSync(file, "utf8"));
105+ } catch {
106+ return 0;
107+ }
108+}
109+
110+function alive(pid) {
111+ if (!pid) return false;
112+ try {
113+ process.kill(pid, 0);
114+ return true;
115+ } catch (e) {
116+ return e.code === "EPERM";
117+ }
118+}
119+
120+const bindable = (port) =>
121+ new Promise((res) => {
122+ const s = createServer();
123+ s.once("error", () => res(false));
124+ s.listen(port, "127.0.0.1", () => s.close(() => res(true)));
125+ });
modifiedapps/diffinery/test/e2e/registry.test.mjs+1−9View file
@@ -14,10 +14,10 @@
1414 import { tmpdir } from "node:os";
1515 import { join, dirname, resolve } from "node:path";
1616 import { fileURLToPath } from "node:url";
17-import { createServer } from "node:net";
1817 import { test, before, after } from "node:test";
1918 import assert from "node:assert/strict";
2019 import { migratedState } from "./d1-state.mjs";
20+import { freePort } from "./ports.mjs";
2121
2222 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2323 const AGENT = resolve(APP, "../../containers/runner/dist/agent.mjs");
@@ -29,14 +29,6 @@
2929 let token;
3030 let owner;
3131
32-const freePort = () =>
33- new Promise((res) => {
34- const s = createServer();
35- s.listen(0, "127.0.0.1", () => {
36- const { port } = s.address();
37- s.close(() => res(port));
38- });
39- });
4032 const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
4133 async function until(what, fn, timeoutMs = 60_000) {
4234 const end = Date.now() + timeoutMs;
modifiedapps/diffinery/test/e2e/review.test.mjs+1−10View file
@@ -15,11 +15,11 @@
1515 import { randomBytes } from "node:crypto";
1616 import { join, dirname, resolve } from "node:path";
1717 import { fileURLToPath } from "node:url";
18-import { createServer as netServer } from "node:net";
1918 import { createServer as httpServer } from "node:http";
2019 import { test, before, after } from "node:test";
2120 import assert from "node:assert/strict";
2221 import { migratedState } from "./d1-state.mjs";
22+import { freePort } from "./ports.mjs";
2323
2424 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2525 const AGENT = resolve(APP, "../../containers/runner/dist/agent.mjs");
@@ -38,15 +38,6 @@
3838 let token;
3939 const modelRequests = [];
4040
41-const freePort = () =>
42- new Promise((res) => {
43- const s = netServer();
44- s.listen(0, "127.0.0.1", () => {
45- const { port } = s.address();
46- s.close(() => res(port));
47- });
48- });
49-
5041 async function api(method, path, body, tok = token) {
5142 const res = await fetch(`${base}/api/v3${path}`, {
5243 method,
modifiedapps/diffinery/test/e2e/security-harness.mjs+1−10View file
@@ -6,10 +6,10 @@
66 import { tmpdir } from "node:os";
77 import { join, dirname, resolve } from "node:path";
88 import { fileURLToPath } from "node:url";
9-import { createServer } from "node:net";
109 import { before, after } from "node:test";
1110 import assert from "node:assert/strict";
1211 import { migratedState } from "./d1-state.mjs";
12+import { freePort } from "./ports.mjs";
1313
1414 export const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
1515 export const work = mkdtempSync(join(tmpdir(), "diffinery-security-"));
@@ -25,15 +25,6 @@
2525 /** One minute of an environment's wait timer, in this Worker (WAIT_TIMER_MINUTE_MS). */
2626 export const TIMER_MINUTE_MS = 10_000;
2727
28-export const freePort = () =>
29- new Promise((res) => {
30- const s = createServer();
31- s.listen(0, "127.0.0.1", () => {
32- const { port } = s.address();
33- s.close(() => res(port));
34- });
35- });
36-
3728 export const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
3829 export async function until(what, fn, timeoutMs = 60_000) {
3930 const end = Date.now() + timeoutMs;
modifiedapps/diffinery/test/e2e/security-txt.test.mjs+1−10View file
@@ -11,24 +11,15 @@
1111 import { tmpdir } from "node:os";
1212 import { join, dirname, resolve } from "node:path";
1313 import { fileURLToPath } from "node:url";
14-import { createServer } from "node:net";
1514 import { test, after } from "node:test";
1615 import assert from "node:assert/strict";
1716 import { migratedState } from "./d1-state.mjs";
17+import { freePort } from "./ports.mjs";
1818
1919 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
2020 const work = mkdtempSync(join(tmpdir(), "diffinery-securitytxt-e2e-"));
2121 const running = [];
2222
23-const freePort = () =>
24- new Promise((res) => {
25- const s = createServer();
26- s.listen(0, "127.0.0.1", () => {
27- const { port } = s.address();
28- s.close(() => res(port));
29- });
30- });
31-
3223 /** Start a Worker with extra `--var`s and seed SQL; resolves to its base URL once /healthz answers. */
3324 async function worker(name, vars, seed = []) {
3425 const port = await freePort();
modifiedapps/diffinery/test/e2e/status.test.mjs+1−10View file
@@ -10,24 +10,15 @@
1010 import { tmpdir } from "node:os";
1111 import { join, dirname, resolve } from "node:path";
1212 import { fileURLToPath } from "node:url";
13-import { createServer } from "node:net";
1413 import { test, after } from "node:test";
1514 import assert from "node:assert/strict";
1615 import { migratedState } from "./d1-state.mjs";
16+import { freePort } from "./ports.mjs";
1717
1818 const APP = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
1919 const work = mkdtempSync(join(tmpdir(), "diffinery-status-e2e-"));
2020 const running = [];
2121
22-const freePort = () =>
23- new Promise((res) => {
24- const s = createServer();
25- s.listen(0, "127.0.0.1", () => {
26- const { port } = s.address();
27- s.close(() => res(port));
28- });
29- });
30-
3122 /** Start a Worker with extra `--var`s and seed SQL; resolves to its base URL once /healthz answers. */
3223 async function worker(name, vars, seed = []) {
3324 const port = await freePort();
modifiedapps/diffinery/test/e2e/tasks.test.mjs+1−1View file
@@ -39,7 +39,6 @@
3939 token,
4040 modelRequests,
4141 jailToken,
42- freePort,
4342 api,
4443 ok,
4544 asPerson,
@@ -49,6 +48,7 @@
4948 mcp,
5049 poolSandboxes,
5150 } from "./agents-harness.mjs";
51+import { freePort } from "./ports.mjs";
5252
5353 test("model keys: write-only, browser session only, with an opt-in", async () => {
5454 assert.deepEqual(await ok("GET", "/diffinery/model-keys"), []);
modifiedapps/diffinery/test/e2e/terminals.test.mjs+1−1View file
@@ -31,7 +31,6 @@
3131 poolLog,
3232 token,
3333 modelRequests,
34- freePort,
3534 api,
3635 ok,
3736 asPerson,
@@ -41,6 +40,7 @@
4140 mcp,
4241 poolSandboxes,
4342 } from "./agents-harness.mjs";
43+import { freePort } from "./ports.mjs";
4444
4545 /** Opens a terminal's WebSocket; resolves with the HTTP status when the upgrade is refused. */
4646 function termSocket(url, headers) {