testRegistryMirrorsSignedReleases

tcmts.registry.test.testRegistryMirrorsSignedReleases · #qpjnsbuv · term

The registry, against the fake network: Jetstream's events become rows (cursor kept), each release is checked against its author's signed record before its code is mirrored by hash, mounted by DID, with the libraries it holds noted (the libraries its author uses); a forged record, or one no repository holds, fails; a deleted one is withdrawn, its code kept. What an event says changes nothing until the repository says it too: a lying Jetstream can't change a release's notes or sources, nor withdraw it.

import { addLibrary } from "#codebase/tcmts/cli/libraries";
import { startFakeAtproto } from "#codebase/tcmts/cli/test/e2e/examples";
import { tempDir, withChildren } from "#codebase/tcmts/cli/test/e2e/harness";
import { IR_VERSION } from "#codebase/tcmts/core/hash";
import {
  cursors, librariesUsed, readJetstream, registryCodebase, releases, takeEvent, uses,
} from "#codebase/tcmts/registry";
import { codebaseHolding, readFromTheStart, served, withEnv } from "#codebase/tcmts/registry/test";
import { runJobs } from "#codebase/tcmts/server";
import type { RawEvent } from "@bsky/jetstream";
import assert from "node:assert/strict";

export const testRegistryMirrorsSignedReleases = () =>
  withChildren(async (keep) => {
    const alice = {
      did: "did:plc:alice000000000000000000",
      handle: "alice.test",
      password: "a-pass",
      // (her DID document as dev-env's PLC serves it: a legacy, uncompressed secp256k1 key)
      legacyKey: true,
    };
    const net = await startFakeAtproto(keep, [alice]);
    const shapes = codebaseHolding(
      "shapes",
      "// tcm: namespace shapes\nexport const sq = (n: number) => n * n;\n",
      "shapes",
    );
    const geo = codebaseHolding(
      "geo",
      "// tcm: namespace geo\nexport const area = (side: number) => side * side;\n",
      "geo",
    );
    // geo holds shapes as a library of its own (fetched from its server: a directory, in a test process, would be
    // the codebase the test runs in, which `TCM_CODEBASE` names)
    await addLibrary(geo.cb, {
      name: "shapes",
      source: await served(keep, shapes.cb),
      what: `#${await shapes.namespace()}`,
      at: "geo.lib.shapes",
    });
    const source = await served(keep, geo.cb);
    const announce = (rkey: string, version: string, namespace: string) =>
      net.seed(alice.did, "codes.tcm.release", rkey, {
        package: rkey.slice(0, rkey.indexOf(":")),
        version,
        namespace,
        entry: "x",
        hashFormat: IR_VERSION,
        notes: `## ${version}`,
        sources: [source],
        createdAt: new Date().toISOString(),
      });
    const uri = (rkey: string) => `at://${alice.did}/codes.tcm.release/${rkey}`;
    const row = async (rkey: string) => (await releases.findOne({ uri: uri(rkey) }))?.value;
    announce("geo:1.0.0", "1.0.0", await geo.namespace());
    announce("shapes:0.1.0", "0.1.0", await shapes.namespace());
    announce("geo:1.1.0", "1.1.0", await geo.namespace());
    net.forge(uri("geo:1.1.0"));
    net.unsigned(alice.did, "codes.tcm.release", "geo:2.0.0", {
      package: "geo",
      version: "2.0.0",
      namespace: await geo.namespace(),
      entry: "x",
      hashFormat: IR_VERSION,
      notes: "",
      sources: [source],
      createdAt: new Date().toISOString(),
    });

    await withEnv(
      {
        TCM_ATPROTO_DIRECTORY: net.url,
        TCM_ATPROTO_LOCAL: "1",
        TCM_JETSTREAM: net.url,
        TCM_RELAY: net.url,
        TCM_REGISTRY_CODEBASE: tempDir("registry mirror"),
        JETSTREAM_API_KEY: "",
      },
      async () => {
        await readFromTheStart();
        assert.equal((await readJetstream({ idleMs: 500 })).events, 4);
        assert.equal((await row("geo:1.0.0"))?.state, "pending");
        await runJobs({ all: true });

        // mirrored, its author checked, its code by hash, mounted by DID
        const g = (await row("geo:1.0.0"))!;
        assert.equal(g.state, "mirrored", g.reason);
        assert.ok(g.verifiedAt);
        assert.equal(g.mount, "plc_alice000000000000000000.geo.v1_0_0");
        assert.equal(g.from, source);
        const names = registryCodebase()
          .store.names()
          .map((n) => n.path);
        assert.ok(names.includes("plc_alice000000000000000000.geo.v1_0_0.area"), names.join("\n"));
        assert.ok(names.includes("plc_alice000000000000000000.geo.v1_0_0.lib.shapes.sq"));
        // who uses what, exactly: geo holds shapes's namespace
        const held = await uses.find({ uri: uri("geo:1.0.0") });
        assert.deepEqual(
          held.map((u) => [u.value.at, u.value.namespace]),
          [["lib.shapes", await shapes.namespace()]],
        );
        assert.equal(
          (await uses.find({ namespace: (await row("shapes:0.1.0"))!.namespace })).length,
          1,
        );
        // (so the libraries she uses, as her releases say: shapes)
        assert.deepEqual([...(await librariesUsed(alice.did))], [`${alice.did} shapes`]);

        // a record signed by another key, and one no repository holds: never shown as hers
        assert.equal((await row("geo:1.1.0"))?.state, "failed");
        assert.match(
          (await row("geo:1.1.0"))!.reason!,
          /doesn't check against .*signed repository/,
        );
        assert.equal((await row("geo:2.0.0"))?.state, "failed");
        assert.match(
          (await row("geo:2.0.0"))!.reason!,
          /repository has no codes\.tcm\.release\/geo:2\.0\.0/,
        );

        // the cursor's kept: a second read sees only what's new; a deleted record withdraws it, keeping its code
        const seq = (await cursors.findOne({ feed: "jetstream" }))!.value.seq;
        assert.equal((await readJetstream({ idleMs: 500 })).events, 0);
        const del = await fetch(`${net.url}/xrpc/com.atproto.repo.deleteRecord`, {
          method: "POST",
          headers: {
            authorization: `Bearer acc-${alice.did}`,
            "content-type": "application/json",
          },
          body: JSON.stringify({
            repo: alice.did,
            collection: "codes.tcm.release",
            rkey: "shapes:0.1.0",
          }),
        });
        assert.equal(del.status, 200);
        assert.equal((await readJetstream({ idleMs: 500 })).events, 1);
        await runJobs({ all: true });
        assert.ok((await cursors.findOne({ feed: "jetstream" }))!.value.seq > seq);
        assert.equal((await row("shapes:0.1.0"))?.state, "withdrawn");
        assert.ok(
          registryCodebase()
            .store.names()
            .some((n) => n.path.startsWith("plc_alice000000000000000000.shapes.v0_1_0.")),
        );

        // a record the registry never checked, deleted, is gone (not withdrawn: it names nobody's code)
        await fetch(`${net.url}/xrpc/com.atproto.repo.deleteRecord`, {
          method: "POST",
          headers: { authorization: `Bearer acc-${alice.did}`, "content-type": "application/json" },
          body: JSON.stringify({
            repo: alice.did,
            collection: "codes.tcm.release",
            rkey: "geo:1.1.0",
          }),
        });
        await readJetstream({ idleMs: 500 });
        await runJobs({ all: true });
        assert.equal(await row("geo:1.1.0"), undefined);

        // events that lie (an update the repository doesn't hold, a delete of a record it does) change nothing
        const lie = (operation: string, record?: Record<string, unknown>) =>
          takeEvent({
            kind: "commit",
            did: alice.did,
            seq: 0,
            time: new Date().toISOString(),
            commit: {
              operation,
              collection: "codes.tcm.release",
              rkey: "geo:1.0.0",
              rev: "",
              cid: "c",
              ...(record ? { record } : {}),
            },
          } as unknown as RawEvent);
        const before = (await row("geo:1.0.0"))!;
        await lie("update", {
          $type: "codes.tcm.release",
          package: "geo",
          version: "1.0.0",
          namespace: before.namespace,
          entry: "x",
          hashFormat: IR_VERSION,
          notes: "## pwned",
          sources: ["https://evil.example"],
          createdAt: new Date().toISOString(),
        });
        await lie("delete");
        await runJobs({ all: true });
        const after = (await row("geo:1.0.0"))!;
        assert.equal(after.state, "mirrored");
        assert.equal(after.notes, "## 1.0.0");
        assert.deepEqual(after.sources, [source]);

        // a version announced again as another namespace fails
        announce("geo:1.0.0", "1.0.0", await shapes.namespace());
        await readJetstream({ idleMs: 500 });
        await runJobs({ all: true });
        assert.equal((await row("geo:1.0.0"))?.state, "failed");
        assert.match((await row("geo:1.0.0"))!.reason!, /announced again as #\w+, after #\w+/);
      },
    );
  })

uses