testServeRunOn

tcmts.cli.test.e2e.sync.testServeRunOn · #a6awstz5 · term

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);
  })

uses