testServeRunOn
tcm serve: run --on sends missing code, streams output, and rejects tampered definitions (or keeps none of what they claim)
import { tempDir, withChildren } from "#codebase/tcmts/cli/test/e2e/harness"; import { codebase, startServer } from "#codebase/tcmts/cli/test/e2e/sync"; import assert from "node:assert/strict"; import fs from "node:fs"; export const testServeRunOn = () => withChildren(async (keep) => { const root = tempDir("sync"); const server = codebase(root, "server"); const client = codebase(root, "client"); const url = await startServer(keep, server.dir, "tok"); client.scratch(`export const fib = (n: number): number => (n < 2 ? n : fib(n - 1) + fib(n - 2)); export const report = (n: string) => { console.log("cwd " + process.cwd()); return \`fib(\${n}) = \${fib(Number(n))}\`; }; `); client.tcm("add"); client.tcm("remote", "add", "srv", url, "--token", "tok"); const out = client.tcm("run", "report", "20", "--on", "srv"); assert.match(out, /sent 2 definition\(s\)/); assert.match( out, new RegExp(`cwd ${fs.realpathSync(server.dir).replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`), "ran in the server's codebase", ); assert.match(out, /fib\(20\) = 6765/); assert.doesNotMatch( client.tcm("run", "report", "5", "--on", "srv"), /sent/, "nothing to send the second time", ); client.tcm("remote", "add", "wrong", url, "--token", "nope"); assert.throws( () => client.tcm("run", "report", "1", "--on", "wrong"), /missing or wrong token/, ); // fetch an honest record from the client, then try to slip altered source past the server under the same hash client.scratch(`export const greet = (name: string) => \`hello \${name}\`;\n`); client.tcm("add"); const clientUrl = await startServer(keep, client.dir, "tok2"); const call = async (base: string, token: string, route: string, body: unknown) => { const res = await fetch(`${base}/${route}`, { method: "POST", headers: { authorization: `Bearer ${token}` }, body: JSON.stringify(body), }); return { status: res.status, body: (await res.json()) as any }; }; const branch = (await call(clientUrl, "tok2", "branch", { name: "main" })).body.branch; const greetHash = branch.names.find((n: { path: string }) => n.path === "greet").hash as string; const [rec] = (await call(clientUrl, "tok2", "get", { hashes: [greetHash] })).body.records; const evil = { ...rec, sourceText: rec.sourceText.replace("`hello ${name}`", '"pwned"') }; const rejected = await call(url, "tok", "put", { records: [evil] }); assert.equal(rejected.status, 400); assert.match(rejected.body.error, /source does not match their hashes/); // nor is IR sent beside honest source: the server keeps the IR it derives from the source const evilIr = rec.ir.replace('"hello "', '"pwned "'); assert.notEqual(evilIr, rec.ir); assert.deepEqual((await call(url, "tok", "put", { records: [{ ...rec, ir: evilIr }] })).body, { stored: 1, }); const [kept] = (await call(url, "tok", "get", { hashes: [greetHash] })).body.records; assert.equal(kept.ir, rec.ir); })