/** * @file remote-hub.test.js * @description The hub half of the remote-clients architecture (server/hub/), * in server mode: device enrollment by password (token shown once, stored as * a hash, 90 days, revocable), session registration (UUID, one device per * session, no hijack of a known session), the gateway (device token → pool * account's OAuth token, never the reverse; only registered sessions, `warn` * records an unmonitored one, `block` refuses; usage counted from SSE and * JSON answers; one account per session), the hourly upload (offset protocol, * fixed file shapes only, the SAME importer so tokens land, owner_id/source * stamped, scope: a developer sees only their own), retention purge, the * signed-in views (devices, revoke with the password again + audit, "who * opened my sessions"). * @author Nguyễn Ngọc Trí Vĩ */ const { describe, it, before, after } = require("node:test"); const assert = require("node:assert/strict"); const crypto = require("node:crypto"); const http = require("node:http"); const path = require("node:path"); const fs = require("node:fs"); const os = require("node:os"); const TMP = fs.mkdtempSync(path.join(os.tmpdir(), "remote-hub-")); process.env.DASHBOARD_DB_PATH = path.join(TMP, "dashboard.db"); process.env.CLAUDE_HOME = path.join(TMP, ".claude"); process.env.CODEX_HOME = path.join(TMP, ".codex"); process.env.DASHBOARD_DATA_DIR = path.join(TMP, "data"); process.env.DASHBOARD_LIVENESS_PROBE = "0"; process.env.AGENTHUB_REMOTE_REGISTER_GRACE_MS = "300"; process.env.AGENTHUB_REMOTE_UNMONITORED_ALERT_MS = "250"; process.env.AGENTHUB_REMOTE_FLUSH_MS = "250"; require("../lib/cc-usage").fetchUsage = async () => ({}); require("../lib/cc-usage").fetchOwner = async () => null; let createApp; let startServer; let db; let auth; let server; let BASE; let upstream; let seen = []; const POOL_TOKEN = `sk-ant-oat01-${"p".repeat(40)}`; const users = {}; const sid = () => crypto.randomUUID(); async function call(method, p, { token, cookie, body, headers = {} } = {}) { const res = await fetch(BASE + p, { method, headers: { "content-type": "application/json", ...(token ? { authorization: `Bearer ${token}` } : {}), ...(cookie ? { cookie } : {}), ...headers, }, body: body !== undefined ? JSON.stringify(body) : undefined, }); const text = await res.text(); let json = null; try { json = JSON.parse(text); } catch { /* stream */ } return { status: res.status, body: json, text, headers: res.headers }; } async function login(username, password) { const res = await fetch(BASE + "/api/auth/login", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ username, password }), }); return res.headers.get("set-cookie").split(";")[0]; } async function enroll(username, password, deviceName = "laptop") { return call("POST", "/api/remote/device/login", { body: { username, password, deviceName } }); } function transcript(sessionId, cwd, { input = 10, output = 5, text = "hello" } = {}) { return ( [ { type: "user", sessionId, timestamp: "2026-11-04T01:00:00.000Z", cwd, message: { content: "do the thing" }, }, { type: "assistant", sessionId, timestamp: "2026-11-04T01:00:01.000Z", cwd, message: { id: `msg_${input}_${output}`, model: "claude-sonnet-4-5-20250929", content: [{ type: "text", text }], usage: { input_tokens: input, output_tokens: output, cache_read_input_tokens: 0, cache_creation_input_tokens: 0, }, }, }, ] .map((l) => JSON.stringify(l)) .join("\n") + "\n" ); } before(async () => { upstream = http.createServer((req, res) => { let raw = ""; req.on("data", (c) => (raw += c)); req.on("end", () => { seen.push({ url: req.url, headers: req.headers, body: raw }); const asked = JSON.parse(raw || "{}"); if (asked.gzip) { // As api.anthropic.com answers a client that accepts it: compressed. const zlib = require("node:zlib"); const sse = 'event: message_start\ndata: {"type":"message_start","message":{"usage":{"input_tokens":11,"cache_read_input_tokens":0,"cache_creation_input_tokens":0,"output_tokens":1}}}\n\n' + 'event: message_delta\ndata: {"type":"message_delta","usage":{"output_tokens":22}}\n\n'; res.writeHead(200, { "content-type": "text/event-stream", "content-encoding": "gzip" }); res.end(zlib.gzipSync(sse)); return; } if (asked.stream) { res.writeHead(200, { "content-type": "text/event-stream" }); res.write( 'event: message_start\ndata: {"type":"message_start","message":{"usage":{"input_tokens":100,"cache_read_input_tokens":40,"cache_creation_input_tokens":7,"output_tokens":1}}}\n\n' ); setTimeout( () => res.end( 'event: message_delta\ndata: {"type":"message_delta","usage":{"output_tokens":25}}\n\n' ), 20 ); return; } res.writeHead(200, { "content-type": "application/json" }); res.end(JSON.stringify({ ok: true, usage: { input_tokens: 3, output_tokens: 4 } })); }); }); await new Promise((r) => upstream.listen(0, "127.0.0.1", r)); process.env.AGENTHUB_REMOTE_UPSTREAM = `http://127.0.0.1:${upstream.address().port}`; process.env.AGENTHUB_MODE = "server"; ({ createApp, startServer } = require("../index")); ({ db } = require("../db")); auth = require("../lib/auth"); server = await startServer(createApp(), 0); BASE = `http://127.0.0.1:${server.address().port}`; users.boss = await auth.createUser("boss", "admin-pass-1", "admin"); users.mia = await auth.createUser("mia", "member-pass-1", "developer"); users.tom = await auth.createUser("tom", "member-pass-2", "developer"); require("../lib/claude-pool").addAccount("team", POOL_TOKEN); }); after(() => { delete process.env.AGENTHUB_MODE; delete process.env.AGENTHUB_REMOTE_UPSTREAM; delete process.env.AGENTHUB_REMOTE_GATE; server?.close(); upstream?.close(); fs.rmSync(TMP, { recursive: true, force: true }); }); describe("device enrollment", () => { it("gives a token once for the right password, stores only its hash, 90 days", async () => { const r = await enroll("mia", "member-pass-1", "mia-laptop"); assert.equal(r.status, 200); assert.match(r.body.token, /^ahdev_[A-Za-z0-9_-]{43}$/); assert.equal(r.body.user.username, "mia"); assert.equal(r.body.device.name, "mia-laptop"); const days = (Date.parse(r.body.device.expiresAt) - Date.now()) / 864e5; assert.ok(days > 89 && days <= 90, `expires in ${days} days`); const row = db.prepare("SELECT * FROM devices WHERE id = ?").get(r.body.device.id); assert.notEqual(row.token_hash, r.body.token); assert.ok(!JSON.stringify(row).includes(r.body.token)); const me = await call("GET", "/api/remote/device/me", { token: r.body.token }); assert.equal(me.status, 200); assert.equal(me.body.user.username, "mia"); assert.ok(!JSON.stringify(me.body).includes("token_hash")); }); it("refuses a wrong password and a disabled user", async () => { assert.equal((await enroll("mia", "wrong-pass")).status, 401); await auth.createUser("gone", "gone-pass-1", "developer"); auth.setDisabled("gone", true); assert.equal((await enroll("gone", "gone-pass-1")).status, 401); }); it("a revoked, expired or disabled-user token opens nothing", async () => { const r = await enroll("tom", "member-pass-2"); const t = r.body.token; assert.equal((await call("GET", "/api/remote/device/me", { token: t })).status, 200); db.prepare("UPDATE devices SET expires_at = '2000-01-01T00:00:00Z' WHERE id = ?").run( r.body.device.id ); assert.equal((await call("GET", "/api/remote/device/me", { token: t })).status, 401); const r2 = await enroll("tom", "member-pass-2"); assert.equal( (await call("POST", "/api/remote/device/logout", { token: r2.body.token, body: {} })).status, 200 ); assert.equal( (await call("GET", "/api/remote/device/me", { token: r2.body.token })).status, 401 ); assert.equal( (await call("GET", "/api/remote/device/me", { token: "ahdev_" + "x".repeat(43) })).status, 401 ); }); it("a device token is no login: cookie routes refuse it", async () => { const r = await enroll("mia", "member-pass-1"); const res = await call("GET", "/api/sessions", { token: r.body.token }); assert.equal(res.status, 401); }); }); describe("session registration", () => { let mia; let tom; before(async () => { mia = (await enroll("mia", "member-pass-1")).body.token; tom = (await enroll("tom", "member-pass-2")).body.token; }); it("takes a UUID + absolute folder, refuses anything else", async () => { const id = sid(); const ok = await call("POST", "/api/remote/device/sessions", { token: mia, body: { sessionId: id, cwd: "/home/mia/proj" }, }); assert.equal(ok.status, 200); assert.equal(ok.body.sessionId, id); for (const body of [ { sessionId: "not-a-uuid", cwd: "/x" }, { sessionId: sid(), cwd: "relative/path" }, { sessionId: sid(), cwd: "/x", tool: "codex" }, ]) { const r = await call("POST", "/api/remote/device/sessions", { token: mia, body }); assert.equal(r.status, 400, JSON.stringify(body)); } }); it("one session belongs to one device; a known local session cannot be claimed", async () => { const id = sid(); await call("POST", "/api/remote/device/sessions", { token: mia, body: { sessionId: id, cwd: "/a" }, }); const again = await call("POST", "/api/remote/device/sessions", { token: mia, body: { sessionId: id, cwd: "/a" }, }); assert.equal(again.status, 200, "re-registering (a resume) is fine"); const theft = await call("POST", "/api/remote/device/sessions", { token: tom, body: { sessionId: id, cwd: "/a" }, }); assert.equal(theft.status, 409); // The same user enrolled again (a new device) resumes it: it moves along. const mia2 = (await enroll("mia", "member-pass-1", "mia-new")).body.token; const moved = await call("POST", "/api/remote/device/sessions", { token: mia2, body: { sessionId: id, cwd: "/a" }, }); assert.equal(moved.status, 200); const back = await call("POST", "/api/remote/device/sessions", { token: mia, body: { sessionId: id, cwd: "/a" }, }); assert.equal(back.status, 200, "and back"); const local = sid(); db.prepare( "INSERT INTO sessions (id, name, status, cwd) VALUES (?, 'local', 'active', '/w')" ).run(local); const claim = await call("POST", "/api/remote/device/sessions", { token: tom, body: { sessionId: local, cwd: "/w" }, }); assert.equal(claim.status, 409); }); }); describe("enrollment and registration edges", () => { it("a temporary password (must change) cannot enroll a machine", async () => { db.prepare("UPDATE users SET must_change_password = 1 WHERE username = 'mia'").run(); try { const r = await enroll("mia", "member-pass-1", "temp-box"); assert.equal(r.status, 403); assert.equal(r.body.error.code, "EPWCHANGE"); assert.equal(r.body.token, undefined); } finally { db.prepare("UPDATE users SET must_change_password = 0 WHERE username = 'mia'").run(); } }); it("a session keeps the folder it was first registered with", async () => { const t = (await enroll("mia", "member-pass-1", "cwd-box")).body.token; const id = sid(); await call("POST", "/api/remote/device/sessions", { token: t, body: { sessionId: id, cwd: "/a" }, }); await call("POST", "/api/remote/device/sessions", { token: t, body: { sessionId: id, cwd: "/b" }, }); assert.equal( db.prepare("SELECT cwd FROM remote_sessions WHERE session_id = ?").get(id).cwd, "/a" ); }); it("a purged session cannot be registered again", async () => { const t = (await enroll("mia", "member-pass-1", "purge-box")).body.token; const id = sid(); await call("POST", "/api/remote/device/sessions", { token: t, body: { sessionId: id, cwd: "/a" }, }); db.prepare("UPDATE remote_sessions SET purged_at = '2026-01-01' WHERE session_id = ?").run(id); const r = await call("POST", "/api/remote/device/sessions", { token: t, body: { sessionId: id, cwd: "/a" }, }); assert.equal(r.status, 410); assert.equal(r.body.error.code, "EPURGED"); }); }); describe("the gateway", () => { let token; let deviceId; before(async () => { const r = await enroll("mia", "member-pass-1", "gw-box"); token = r.body.token; deviceId = r.body.device.id; }); const register = (id) => call("POST", "/api/remote/device/sessions", { token, body: { sessionId: id, cwd: "/home/mia/p" }, }); it("relays a registered session with the pool's OAuth token, never the device token", async () => { const id = sid(); await register(id); seen = []; const r = await call("POST", "/api/remote/gw/v1/messages?beta=true", { token, headers: { "x-claude-code-session-id": id, "anthropic-beta": "claude-code-20250219", "anthropic-version": "2023-06-01", }, body: { model: "m", messages: [] }, }); assert.equal(r.status, 200); assert.equal(seen.length, 1); const got = seen[0]; assert.equal(got.url, "/v1/messages?beta=true"); assert.equal(got.headers.authorization, `Bearer ${POOL_TOKEN}`); assert.equal(got.headers["x-api-key"], undefined); assert.equal(got.headers["anthropic-beta"], "claude-code-20250219,oauth-2025-04-20"); assert.ok(!JSON.stringify(got.headers).includes("ahdev_")); assert.ok(!r.text.includes(POOL_TOKEN), "the pool token never reaches the client"); const row = db.prepare("SELECT * FROM remote_sessions WHERE session_id = ?").get(id); assert.equal(row.account, "team"); assert.equal(row.requests, 1); assert.equal(row.gw_input_tokens, 3); assert.equal(row.gw_output_tokens, 4); }); it("counts usage from a streamed answer and passes the stream through", async () => { const id = sid(); await register(id); const r = await call("POST", "/api/remote/gw/v1/messages", { token, headers: { "x-claude-code-session-id": id }, body: { stream: true }, }); assert.equal(r.status, 200); assert.match(r.text, /message_start[\s\S]*message_delta/); const row = db.prepare("SELECT * FROM remote_sessions WHERE session_id = ?").get(id); assert.equal(row.gw_input_tokens, 100); assert.equal(row.gw_cache_read_tokens, 40); assert.equal(row.gw_cache_write_tokens, 7); assert.equal(row.gw_output_tokens, 25); }); it("counts usage from a compressed answer and relays the bytes as they came", async () => { const id = sid(); await register(id); const res = await fetch(`${BASE}/api/remote/gw/v1/messages`, { method: "POST", headers: { "content-type": "application/json", authorization: `Bearer ${token}`, "x-claude-code-session-id": id, }, body: JSON.stringify({ gzip: true }), }); assert.equal(res.status, 200); assert.equal(res.headers.get("content-encoding"), "gzip"); assert.match(await res.text(), /message_delta/); // fetch inflates it for us const row = db.prepare("SELECT * FROM remote_sessions WHERE session_id = ?").get(id); assert.equal(row.gw_input_tokens, 11); assert.equal(row.gw_output_tokens, 22); }); it("waits out a registration that is still on its way", async () => { const id = sid(); const req = call("POST", "/api/remote/gw/v1/messages", { token, headers: { "x-claude-code-session-id": id }, body: {}, }); setTimeout(() => register(id), 80); const r = await req; assert.equal(r.status, 200); assert.equal( db.prepare("SELECT unmonitored FROM remote_sessions WHERE session_id = ?").get(id) .unmonitored, 0 ); }); it("warn: an unregistered session is relayed and recorded as unmonitored", async () => { delete process.env.AGENTHUB_REMOTE_GATE; const id = sid(); const r = await call("POST", "/api/remote/gw/v1/messages", { token, headers: { "x-claude-code-session-id": id }, body: {}, }); assert.equal(r.status, 200); const row = db.prepare("SELECT * FROM remote_sessions WHERE session_id = ?").get(id); assert.equal(row.unmonitored, 1); assert.equal(row.device_id, deviceId); }); it("warn: an unmonitored session raises the remote_unmonitored alert; a late registration clears it and alerts nobody", async () => { delete process.env.AGENTHUB_REMOTE_GATE; const alerts = require("../lib/alerts"); assert.deepEqual(alerts.validateRuleConfig("remote_unmonitored", {}), { ok: true, config: {}, }); db.prepare( "INSERT INTO alert_rules (id, name, rule_type, config) VALUES ('ru1', 'outside', 'remote_unmonitored', '{}')" ).run(); alerts.invalidateRuleCache(); try { const gw = (id) => call("POST", "/api/remote/gw/v1/messages", { token, headers: { "x-claude-code-session-id": id }, body: {}, }); const outside = sid(); const late = sid(); assert.equal((await gw(outside)).status, 200); assert.equal((await gw(late)).status, 200); // `late` was only late: its registration arrives before the alert is due. assert.equal((await register(late)).status, 200); assert.equal( db.prepare("SELECT unmonitored FROM remote_sessions WHERE session_id = ?").get(late) .unmonitored, 0 ); await new Promise((r) => setTimeout(r, 450)); const fired = db .prepare("SELECT session_id, message FROM alert_events WHERE rule_id = 'ru1'") .all(); const hit = fired.find((a) => a.session_id === outside); assert.ok(hit, "the session nobody registered alerts"); assert.match(hit.message, /mia on gw-box/); assert.ok(!fired.some((a) => a.session_id === late), "a late registration alerts nobody"); } finally { db.prepare("DELETE FROM alert_rules WHERE id = 'ru1'").run(); alerts.invalidateRuleCache(); } }); it("warn: a message with no session id is still refused, and a known session is never claimed", async () => { delete process.env.AGENTHUB_REMOTE_GATE; seen = []; const bare = await call("POST", "/api/remote/gw/v1/messages", { token, body: {} }); assert.equal(bare.status, 403); assert.equal(bare.body.error.code, "EUNREGISTERED"); const hubOwn = sid(); db.prepare( "INSERT INTO sessions (id, name, status, cwd) VALUES (?, 'hub pane', 'active', '/w')" ).run(hubOwn); const claim = await call("POST", "/api/remote/gw/v1/messages", { token, headers: { "x-claude-code-session-id": hubOwn }, body: {}, }); assert.equal(claim.status, 409); assert.equal( db.prepare("SELECT 1 FROM remote_sessions WHERE session_id = ?").get(hubOwn), undefined ); assert.equal(seen.length, 0, "nothing reached upstream"); }); it("a user over their spend quota is refused (EQUOTA)", async () => { const quota = require("../lib/user-quota"); const real = quota.assertSpawnAllowed; const gw = require("../hub/remote-gateway"); quota.assertSpawnAllowed = () => { throw Object.assign(new Error("over the daily limit"), { code: "EQUOTA" }); }; gw.__resetQuota(); try { const id = sid(); await register(id); seen = []; const r = await call("POST", "/api/remote/gw/v1/messages", { token, headers: { "x-claude-code-session-id": id }, body: {}, }); assert.equal(r.status, 429); assert.equal(r.body.error.code, "EQUOTA"); assert.equal(seen.length, 0); } finally { quota.assertSpawnAllowed = real; gw.__resetQuota(); } }); it("a purged session is not relayed", async () => { const id = sid(); await register(id); db.prepare("UPDATE remote_sessions SET purged_at = '2026-01-01' WHERE session_id = ?").run(id); seen = []; const r = await call("POST", "/api/remote/gw/v1/messages", { token, headers: { "x-claude-code-session-id": id }, body: {}, }); assert.equal(r.status, 410); assert.equal(seen.length, 0); }); it("block: an unregistered session or a message with no session id is refused", async () => { process.env.AGENTHUB_REMOTE_GATE = "block"; try { seen = []; const r = await call("POST", "/api/remote/gw/v1/messages", { token, headers: { "x-claude-code-session-id": sid() }, body: {}, }); assert.equal(r.status, 403); assert.equal(r.body.error.code, "EUNREGISTERED"); const bare = await call("POST", "/api/remote/gw/v1/messages", { token, body: {} }); assert.equal(bare.status, 403); assert.equal(seen.length, 0, "nothing reached upstream"); const id = sid(); await register(id); const ok = await call("POST", "/api/remote/gw/v1/messages", { token, headers: { "x-claude-code-session-id": id }, body: {}, }); assert.equal(ok.status, 200); } finally { delete process.env.AGENTHUB_REMOTE_GATE; } }); it("refuses a bad token, another device's session and a path outside /v1/", async () => { assert.equal( (await call("POST", "/api/remote/gw/v1/messages", { token: "nope", body: {} })).status, 401 ); const id = sid(); await register(id); const other = (await enroll("tom", "member-pass-2")).body.token; const r = await call("POST", "/api/remote/gw/v1/messages", { token: other, headers: { "x-claude-code-session-id": id }, body: {}, }); assert.equal(r.status, 409); seen = []; assert.equal((await call("GET", "/api/remote/gw/api/oauth/usage", { token })).status, 400); // fetch folds the `..` away: the request never reaches the gateway at all. assert.notEqual((await call("GET", "/api/remote/gw/v1/../../etc", { token })).status, 200); assert.equal(seen.length, 0, "nothing reached upstream"); }); it("keeps a session on the account it started on", async () => { const id = sid(); await register(id); db.prepare("UPDATE remote_sessions SET account = 'team' WHERE session_id = ?").run(id); require("../lib/claude-pool").addAccount("aaa-first", `sk-ant-oat01-${"q".repeat(40)}`); try { seen = []; await call("POST", "/api/remote/gw/v1/messages", { token, headers: { "x-claude-code-session-id": id }, body: {}, }); assert.equal(seen[0].headers.authorization, `Bearer ${POOL_TOKEN}`); } finally { require("../lib/claude-pool").removeAccount("aaa-first"); } }); }); describe("the hourly upload", () => { let mia; let tom; let miaCookie; let tomCookie; before(async () => { mia = (await enroll("mia", "member-pass-1", "mia-pc")).body.token; tom = (await enroll("tom", "member-pass-2", "tom-pc")).body.token; miaCookie = await login("mia", "member-pass-1"); tomCookie = await login("tom", "member-pass-2"); }); it("appends at the hub's offset, imports with the local importer, stamps owner and source", async () => { const id = sid(); const cwd = "/home/mia/shop"; await call("POST", "/api/remote/device/sessions", { token: mia, body: { sessionId: id, cwd } }); const part1 = transcript(id, cwd); const r1 = await call("POST", "/api/remote/device/upload", { token: mia, body: { sessionId: id, files: [{ path: `${id}.jsonl`, from: 0, to: Buffer.byteLength(part1), data: part1 }], }, }); assert.equal(r1.status, 200, JSON.stringify(r1.body)); const s = db.prepare("SELECT * FROM sessions WHERE id = ?").get(id); assert.ok(s, "the importer made the session row"); assert.equal(s.owner_id, users.mia.id); assert.match(s.source, /^device:\d+$/); const tok = db .prepare( "SELECT SUM(input_tokens) AS i, SUM(output_tokens) AS o FROM token_usage WHERE session_id = ?" ) .get(id); assert.equal(tok.i, 10); assert.equal(tok.o, 5); // A wrong offset is told where the hub stands; nothing is written. const bad = await call("POST", "/api/remote/device/upload", { token: mia, body: { sessionId: id, files: [{ path: `${id}.jsonl`, from: 0, to: 10, data: "x\n" }] }, }); assert.equal(bad.status, 409); assert.equal(bad.body.error.expected.consumed, Buffer.byteLength(part1)); // Scope: mia sees it, tom does not, the admin does. const own = await call("GET", "/api/sessions?limit=100", { cookie: miaCookie }); assert.ok(JSON.stringify(own.body).includes(id)); const other = await call("GET", "/api/sessions?limit=100", { cookie: tomCookie }); assert.ok(!JSON.stringify(other.body).includes(id)); assert.equal((await call("GET", `/api/sessions/${id}`, { cookie: tomCookie })).status, 404); }); it("chunks marked `more` are imported once: by the round's closing request, or after FLUSH_MS", async () => { const tokens = (id) => db.prepare("SELECT SUM(output_tokens) AS o FROM token_usage WHERE session_id = ?").get(id).o; const cwd = "/home/mia/chunks"; const up = (id, body) => call("POST", "/api/remote/device/upload", { token: mia, body: { sessionId: id, ...body } }); const id = sid(); await call("POST", "/api/remote/device/sessions", { token: mia, body: { sessionId: id, cwd } }); const [l1, l2] = transcript(id, cwd).split(/(?<=\n)/); const a = await up(id, { files: [{ path: `${id}.jsonl`, from: 0, to: Buffer.byteLength(l1), data: l1 }], more: true, }); assert.equal(a.status, 200, JSON.stringify(a.body)); const from = Buffer.byteLength(l1); await up(id, { files: [{ path: `${id}.jsonl`, from, to: from + Buffer.byteLength(l2), data: l2 }], more: true, }); assert.equal(tokens(id), null, "nothing imported while the round goes on"); const close = await up(id, { files: [] }); assert.equal(close.status, 200); assert.equal(close.body.imported, true); assert.equal(tokens(id), 5); // A round that stopped half-way is imported FLUSH_MS later. const id2 = sid(); await call("POST", "/api/remote/device/sessions", { token: mia, body: { sessionId: id2, cwd } }); const t2 = transcript(id2, cwd, { output: 7 }); await up(id2, { files: [{ path: `${id2}.jsonl`, from: 0, to: Buffer.byteLength(t2), data: t2 }], more: true, }); assert.equal(tokens(id2), null); await new Promise((r) => setTimeout(r, 500)); assert.equal(tokens(id2), 7); assert.deepEqual(require("../hub/remote-ingest").__pending(), []); }); it("a session moved to the user's new device keeps its copy and offsets", async () => { const id = sid(); await call("POST", "/api/remote/device/sessions", { token: mia, body: { sessionId: id, cwd: "/m" }, }); const t1 = transcript(id, "/m", { input: 1, output: 2 }); const first = await call("POST", "/api/remote/device/upload", { token: mia, body: { sessionId: id, files: [{ path: `${id}.jsonl`, from: 0, to: Buffer.byteLength(t1), data: t1 }], }, }); assert.equal(first.status, 200, JSON.stringify(first.body)); const newer = (await enroll("mia", "member-pass-1", "mia-reinstalled")).body; await call("POST", "/api/remote/device/sessions", { token: newer.token, body: { sessionId: id, cwd: "/m" }, }); const t2 = transcript(id, "/m", { input: 30, output: 40 }).replace( /2026-11-04T01:00/g, "2026-11-04T02:00" ); const r = await call("POST", "/api/remote/device/upload", { token: newer.token, body: { sessionId: id, files: [ { path: `${id}.jsonl`, from: Buffer.byteLength(t1), to: Buffer.byteLength(t1 + t2), data: t2, }, ], }, }); assert.equal(r.status, 200, JSON.stringify(r.body)); const old = await call("POST", "/api/remote/device/upload", { token: mia, body: { sessionId: id, files: [] }, }); assert.equal(old.status, 404, "the old device no longer holds it"); const s = db.prepare("SELECT source, transcript_path FROM sessions WHERE id = ?").get(id); assert.equal(s.source, `device:${newer.device.id}`); assert.ok(s.transcript_path.includes(`/d${newer.device.id}/`), s.transcript_path); assert.equal(fs.readFileSync(s.transcript_path, "utf8"), t1 + t2, "one file, both parts"); const tok = db .prepare( "SELECT SUM(input_tokens) AS i, SUM(output_tokens) AS o FROM token_usage WHERE session_id = ?" ) .get(id); assert.equal(tok.i, 31); assert.equal(tok.o, 42); }); it("takes only the session's own file shapes, from its own device", async () => { const id = sid(); await call("POST", "/api/remote/device/sessions", { token: mia, body: { sessionId: id, cwd: "/m" }, }); for (const p of [ "../../etc/passwd", `${id}/../x.jsonl`, `other.jsonl`, `${id}/subagents/agent-a/../../x.jsonl`, `${id}/notes.txt`, ]) { const r = await call("POST", "/api/remote/device/upload", { token: mia, body: { sessionId: id, files: [{ path: p, from: 0, to: 2, data: "{}\n" }] }, }); assert.equal(r.status, 400, p); } const sub = await call("POST", "/api/remote/device/upload", { token: mia, body: { sessionId: id, files: [{ path: `${id}/subagents/agent-abc.jsonl`, from: 0, to: 3, data: "{}\n" }], }, }); assert.equal(sub.status, 200); const foreign = await call("POST", "/api/remote/device/upload", { token: tom, body: { sessionId: id, files: [] }, }); assert.equal(foreign.status, 404); const partial = await call("POST", "/api/remote/device/upload", { token: mia, body: { sessionId: id, files: [{ path: `${id}.jsonl`, from: 0, to: 3, data: "abc" }] }, }); assert.equal(partial.status, 400, "half a line is refused"); }); it("purges conversations past retention and keeps the tokens", async () => { const id = sid(); await call("POST", "/api/remote/device/sessions", { token: mia, body: { sessionId: id, cwd: "/m" }, }); const t = transcript(id, "/m", { input: 7, output: 9 }); await call("POST", "/api/remote/device/upload", { token: mia, body: { sessionId: id, files: [{ path: `${id}.jsonl`, from: 0, to: Buffer.byteLength(t), data: t }], ended: true, }, }); assert.ok(db.prepare("SELECT COUNT(*) AS n FROM events WHERE session_id = ?").get(id).n > 0); const ingest = require("../hub/remote-ingest"); const n = ingest.purgeOld({ days: 30, now: Date.now() + 31 * 864e5 }); assert.ok(n >= 1); assert.equal(db.prepare("SELECT COUNT(*) AS n FROM events WHERE session_id = ?").get(id).n, 0); assert.equal( db.prepare("SELECT SUM(output_tokens) AS o FROM token_usage WHERE session_id = ?").get(id).o, 9 ); const row = db.prepare("SELECT * FROM remote_sessions WHERE session_id = ?").get(id); assert.ok(row.purged_at); assert.ok(row.ended_at); const r = await call("POST", "/api/remote/device/upload", { token: mia, body: { sessionId: id, files: [] }, }); assert.equal(r.status, 410); }); }); describe("signed-in views", () => { it("a developer lists only their own devices and revokes one with their password", async () => { const d = (await enroll("mia", "member-pass-1", "to-revoke")).body; const miaCookie = await login("mia", "member-pass-1"); const tomCookie = await login("tom", "member-pass-2"); const mine = await call("GET", "/api/remote/devices", { cookie: miaCookie }); assert.ok(mine.body.devices.every((x) => x.userId === users.mia.id)); const peek = await call("GET", `/api/remote/devices?user=${users.mia.id}`, { cookie: tomCookie, }); assert.ok( peek.body.devices.every((x) => x.userId === users.tom.id), "?user= is ignored for a developer" ); const steal = await call("POST", `/api/remote/devices/${d.device.id}/revoke`, { cookie: tomCookie, body: { password: "member-pass-2" }, }); assert.equal(steal.status, 404); const wrong = await call("POST", `/api/remote/devices/${d.device.id}/revoke`, { cookie: miaCookie, body: { password: "nope" }, }); assert.equal(wrong.status, 403); const ok = await call("POST", `/api/remote/devices/${d.device.id}/revoke`, { cookie: miaCookie, body: { password: "member-pass-1" }, }); assert.equal(ok.status, 200); assert.ok(ok.body.device.revokedAt); assert.equal((await call("GET", "/api/remote/device/me", { token: d.token })).status, 401); }); it("an admin sees a user's devices and remote sessions and revokes with audit", async () => { const d = (await enroll("tom", "member-pass-2", "tom-revoked-by-admin")).body; const boss = await login("boss", "admin-pass-1"); const list = await call("GET", `/api/remote/devices?user=${users.tom.id}`, { cookie: boss }); assert.ok(list.body.devices.some((x) => x.id === d.device.id)); assert.ok(list.body.devices.every((x) => !("token_hash" in x))); const r = await call("POST", `/api/remote/devices/${d.device.id}/revoke`, { cookie: boss, body: { password: "admin-pass-1" }, }); assert.equal(r.status, 200); const a = db .prepare( "SELECT * FROM audit_log WHERE user_id = ? AND owner_id = ? AND path LIKE 'remote device revoked%'" ) .get(users.boss.id, users.tom.id); assert.ok(a); const sessions = await call("GET", `/api/remote/sessions?user=${users.mia.id}`, { cookie: boss, }); assert.equal(sessions.status, 200); assert.ok(sessions.body.sessions.length > 0); assert.ok(sessions.body.sessions.every((s) => s.userId === users.mia.id)); }); it("a user sees who opened their sessions", async () => { const mia = (await enroll("mia", "member-pass-1")).body.token; const id = sid(); await call("POST", "/api/remote/device/sessions", { token: mia, body: { sessionId: id, cwd: "/m" }, }); const t = transcript(id, "/m"); await call("POST", "/api/remote/device/upload", { token: mia, body: { sessionId: id, files: [{ path: `${id}.jsonl`, from: 0, to: Buffer.byteLength(t), data: t }], }, }); const boss = await login("boss", "admin-pass-1"); assert.equal((await call("GET", `/api/sessions/${id}`, { cookie: boss })).status, 200); const miaCookie = await login("mia", "member-pass-1"); const log = await call("GET", "/api/remote/audit", { cookie: miaCookie }); assert.equal(log.status, 200); assert.ok(log.body.entries.some((e) => e.sessionId === id && e.reader === "boss")); }); it("the users page counts a remote session's spend for its owner", async () => { const boss = await login("boss", "admin-pass-1"); const r = await call("GET", `/api/users/${users.mia.id}/details`, { cookie: boss }); assert.equal(r.status, 200); assert.ok(r.body.sessions.total >= 2, JSON.stringify(r.body.sessions)); }); });