~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/atlibs

0
0
main
199 lines · 12.6 KB Raw History
import assert from "node:assert/strict";
import { test } from "node:test";

import { loadModule, modulePin, pdsOf, runModule } from "./index.js";

const did = "did:plc:alice";
const C = "xyz.example.thing";
const uri = (rkey) => `at://${did}/${C}/${rkey}`;

// A stub module: on start each entry makes the calls given for it (ids c0, c1, ...), then waits for them.
const moduleOf = (calls) => ({ module: new Uint8Array(), calls: ["com.atproto.repo.createRecord", "com.atproto.repo.putRecord", "com.atproto.repo.deleteRecord", "com.atproto.repo.applyWrites"], ...calls });
const ledger = () => {
	const rows = new Map();
	return { rows, get: async (id) => rows.get(id) ?? null, put: async (id, data) => void rows.set(id, data), delete: async (id) => rows.delete(id) };
};
const ctxWith = (store, steps) => ({
	storage: store && { managed_records: store },
	wasm: { run: async ({ entry, input }) => (input.event.type === "start" ? { calls: (steps[entry] ?? []).map((call, i) => ({ id: `c${i}`, ...call })) } : {}) },
});
// The run's call log in call order (c0, c1, ...), whatever order they finished in.
const logOf = (ran) => ran.calls.toSorted((a, b) => a.id.localeCompare(b.id));
const pds = async (nsid, { input }) => {
	if (nsid === "com.atproto.repo.createRecord") return { uri: uri(input.rkey ?? "new"), cid: "c" };
	if (nsid === "com.atproto.repo.applyWrites") return { results: input.writes.map((w) => (w.$type.endsWith("#create") ? { uri: uri(w.rkey), cid: "c" } : {})) };
	return {};
};
const write = (nsid, rkey) => ({ nsid, input: { repo: did, collection: C, rkey, ...(nsid !== "com.atproto.repo.deleteRecord" && { record: {} }) } });

test("a module may update and delete what it created, and nothing else", async () => {
	const store = ledger();
	const steps = {
		create: [write("com.atproto.repo.createRecord")],
		put: [write("com.atproto.repo.putRecord", "new"), write("com.atproto.repo.putRecord", "other")],
		del: [write("com.atproto.repo.deleteRecord", "new"), write("com.atproto.repo.deleteRecord", "other")],
	};
	const ctx = ctxWith(store, steps);
	await runModule(ctx, moduleOf(), "create", {}, pds);
	assert.ok(store.rows.has(uri("new")));
	const put = await runModule(ctx, moduleOf(), "put", {}, pds);
	assert.deepEqual(logOf(put).map((c) => c.ok), [true, false]);
	assert.match(logOf(put)[1].error, /putRecord refused: at:\/\/did:plc:alice\/xyz.example.thing\/other was not created by this module/);
	const del = await runModule(ctx, moduleOf(), "del", {}, pds);
	assert.deepEqual(logOf(del).map((c) => c.ok), [true, false]);
	assert.equal(store.rows.has(uri("new")), false);
});

test("the ledger is per module: another module, or an entry with no owner, cannot update or delete", async () => {
	const store = ledger();
	const steps = { create: [write("com.atproto.repo.createRecord")], del: [write("com.atproto.repo.deleteRecord", "new")], old: [write("com.atproto.repo.deleteRecord", "old")] };
	const mine = moduleOf({ id: "at://did:plc:pub/com.fedfork.exec.wasm.module/m" });
	const other = moduleOf({ id: "at://did:plc:evil/com.fedfork.exec.wasm.module/m" });
	await runModule(ctxWith(store, steps), mine, "create", {}, pds);
	assert.equal(store.rows.get(uri("new")).module, mine.id);
	const denied = await runModule(ctxWith(store, steps), other, "del", {}, pds);
	assert.match(logOf(denied)[0].error, /was not created by this module/);
	store.rows.set(uri("old"), { createdAt: "2026-01-01T00:00:00.000Z" }); // written before owners were recorded
	assert.match(logOf(await runModule(ctxWith(store, steps), mine, "old", {}, pds))[0].error, /was not created by this module/);
	assert.equal(logOf(await runModule(ctxWith(store, steps), mine, "del", {}, pds))[0].ok, true);
	assert.ok(!store.rows.has(uri("new")));
	// no id: the module's sha256; owner (a composition's) wins over both
	await runModule(ctxWith(store, steps), moduleOf({ module: Uint8Array.of(1) }), "create", {}, pds);
	assert.equal(store.rows.get(uri("new")).module, "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a");
	await runModule(ctxWith(store, steps), { ...mine, owner: "composition:x" }, "create", {}, pds);
	assert.equal(store.rows.get(uri("new")).module, "composition:x");
});

test("calls and anyRecords must be absent or lists of strings (a string would match substrings)", async () => {
	const ctx = ctxWith(ledger(), {});
	for (const bad of [{ calls: "com.atproto.repo.createRecord" }, { calls: null }, { anyRecords: C }, { anyRecords: [1] }]) {
		await assert.rejects(runModule(ctx, moduleOf(bad), "x", {}, pds), /must be a list of strings/);
	}
	await runModule(ctx, moduleOf({ calls: undefined, anyRecords: [C] }), "x", {}, pds);
});

test("pdsOf: https off the host's network only, unless allowPrivate", async () => {
	const docs = new Map();
	const fetched = [];
	const ctx = { http: { fetch: async (url) => (fetched.push(url), Response.json(docs.get(url) ?? {}, { status: docs.has(url) ? 200 : 404 })) } };
	const doc = (endpoint) => ({ service: [{ id: "#atproto_pds", serviceEndpoint: endpoint }] });
	const plc = (endpoint) => (docs.set("https://plc.directory/did:plc:a", doc(endpoint)), pdsOf(ctx, "did:plc:a"));
	assert.equal(await plc("https://pds.example"), "https://pds.example");
	for (const bad of ["http://pds.example", "https://127.0.0.1", "https://localhost:3000", "https://169.254.169.254/latest", "https://10.1.2.3", "https://172.20.0.1", "https://192.168.1.1", "https://100.64.0.1", "https://0.0.0.0", "https://[::1]", "https://[fd00::1]", "https://[fe80::1]", "https://[::ffff:127.0.0.1]", "https://2130706433", "file:///etc/passwd", "nope"])
		await assert.rejects(plc(bad), /not https|private address|not a URL/, bad);
	fetched.length = 0;
	for (const did of ["did:web:localhost%3A8080", "did:web:127.0.0.1", "did:web:%5B%3A%3A1%5D"]) await assert.rejects(pdsOf(ctx, did), /private address|not a URL/, did);
	assert.deepEqual(fetched, [], "nothing private was fetched");
	docs.set("https://plc.directory/did:plc:a", doc("http://127.0.0.1:2583"));
	assert.equal(await pdsOf(ctx, "did:plc:a", { allowPrivate: true }), "http://127.0.0.1:2583");
	assert.equal(await pdsOf({ ...ctx, allowPrivate: true }, "did:plc:a"), "http://127.0.0.1:2583");
});

test("loadModule: the record's didkey and the at:// URI as id; refuses bad lists and odd replies", async () => {
	const URI = "at://did:plc:pub/com.fedfork.exec.wasm.module/m";
	const cid = "bafkreie5737gdxlw5i64vzichcalba3z2v5n6icifvx5xytvske7mr3hpm";
	let value;
	const ctx = {
		http: {
			fetch: async (url) => {
				if (url.startsWith("https://plc.directory/")) return Response.json({ service: [{ id: "#atproto_pds", serviceEndpoint: "https://pds.example" }] });
				if (url.includes("getRecord")) return Response.json(value);
				return new Response(new Uint8Array([0, 97, 115, 109]));
			},
		},
	};
	const record = (extra) => ({ value: { abi: "emdash-wasm-json-v1", module: { ref: { $link: cid } }, calls: ["a.b.c"], ...extra } });
	value = record({ didkey: { services: ["https://xrpc.fedproxy.com"] } });
	const mod = await loadModule(ctx, URI);
	assert.equal(mod.id, URI);
	assert.deepEqual(mod.didkey, { services: ["https://xrpc.fedproxy.com"] });
	value = record({ calls: "a.b.c" });
	await assert.rejects(loadModule(ctx, URI), /calls must be a list of strings/);
	for (value of [[1, 2], "x", null, {}]) await assert.rejects(loadModule(ctx, URI), /unsupported module ABI/);
});

test("loadModule: <handle>/<name>, <did>/<name> and the at:// URI load the same record; @pin is checked", async () => {
	const URI = "at://did:plc:pub/com.fedfork.exec.wasm.module/m";
	const cid = "bafkreie5737gdxlw5i64vzichcalba3z2v5n6icifvx5xytvske7mr3hpm";
	let claimed = ["at://pub.example"];
	const ctx = {
		http: {
			fetch: async (url) => {
				if (url.includes("resolveHandle")) return new URL(url).searchParams.get("handle") === "pub.example" ? Response.json({ did: "did:plc:pub" }) : new Response("{}", { status: 400 });
				if (url.startsWith("https://plc.directory/")) return Response.json({ alsoKnownAs: claimed, service: [{ id: "#atproto_pds", serviceEndpoint: "https://pds.example" }] });
				if (url.includes("getRecord")) return Response.json({ cid: "bafyrecord", value: { abi: "emdash-wasm-json-v1", module: { ref: { $link: cid } }, calls: ["a.b.c"] } });
				return new Response(new Uint8Array([0, 97, 115, 109]));
			},
		},
	};
	const [byHandle, byDid, byUri] = await Promise.all(["pub.example/m", "did:plc:pub/m", URI].map((ref) => loadModule(ctx, ref)));
	assert.deepEqual([byHandle.id, byDid.id], [URI, URI], "the id is the at:// URI, however it was named");
	assert.deepEqual(byHandle, byUri);
	assert.deepEqual(byDid, byUri);
	const pin = await modulePin(byUri);
	for (const ok of ["pub.example/m@bafyrecord", `pub.example/m@${pin}`, `did:plc:pub/m@${pin.slice(0, 32)}`]) assert.equal((await loadModule(ctx, ok)).id, URI, ok);
	await assert.rejects(loadModule(ctx, `pub.example/m@${pin.slice(0, 31)}`), /at least 32 hex/);
	await assert.rejects(loadModule(ctx, `pub.example/m@${"0".repeat(32)}`), /pub.example\/m@0+: pinned to 0+, but it is pin/);
	await assert.rejects(loadModule(ctx, "nobody.example/m"), /nobody.example did not resolve/);
	claimed = ["at://someone.else"];
	await assert.rejects(loadModule(ctx, "pub.example/m"), /does not claim it/);
});

test("anyRecords opens a collection; without a ledger nothing is managed", async () => {
	const steps = { del: [write("com.atproto.repo.deleteRecord", "x")] };
	const seen = [];
	const call = async (nsid, request) => seen.push(nsid) && {};
	assert.equal(logOf(await runModule(ctxWith(undefined, steps), moduleOf({ anyRecords: [C] }), "del", {}, call))[0].ok, true);
	const refused = await runModule(ctxWith(undefined, steps), moduleOf(), "del", {}, call);
	assert.equal(logOf(refused)[0].ok, false);
	assert.equal(seen.length, 1, "a refused call never reaches the PDS");
	const bare = await runModule(ctxWith(ledger(), { del: [{ nsid: "com.atproto.repo.deleteRecord" }] }), moduleOf(), "del", {}, call);
	assert.match(logOf(bare)[0].error, /refused/, "a write with no input is refused, not thrown");
});

test("applyWrites is checked per write and its creates are remembered", async () => {
	const store = ledger();
	const op = (kind, rkey) => ({ $type: `com.atproto.repo.applyWrites#${kind}`, collection: C, rkey, ...(kind !== "delete" && { value: {} }) });
	const apply = (writes) => [{ nsid: "com.atproto.repo.applyWrites", input: { repo: did, writes } }];
	const ctx = ctxWith(store, { a: apply([op("create", "k1"), op("create", "k2")]), b: apply([op("update", "k1"), op("delete", "k2")]), c: apply([op("delete", "k1"), op("delete", "zz")]) });
	await runModule(ctx, moduleOf(), "a", {}, pds);
	assert.deepEqual([...store.rows.keys()], [uri("k1"), uri("k2")]);
	assert.equal(logOf(await runModule(ctx, moduleOf(), "b", {}, pds))[0].ok, true);
	assert.deepEqual([...store.rows.keys()], [uri("k1")]);
	const c = await runModule(ctx, moduleOf(), "c", {}, pds);
	assert.match(logOf(c)[0].error, /zz was not created/);
	assert.ok(store.rows.has(uri("k1")), "a refused applyWrites changes nothing");
});

test("a pin loads the version publish keeps at <rkey>.<32 hex>, so a republish leaves pinned compositions as they were", async () => {
	const { loadComposition } = await import("../compose/index.js");
	const URI = "at://did:plc:pub/com.fedfork.exec.wasm.module/m";
	const blob = "bafkreie5737gdxlw5i64vzichcalba3z2v5n6icifvx5xytvske7mr3hpm";
	const records = new Map(); // rkey -> value
	const ctx = {
		http: {
			fetch: async (url) => {
				if (url.startsWith("https://plc.directory/")) return Response.json({ service: [{ id: "#atproto_pds", serviceEndpoint: "https://pds.example" }] });
				if (url.includes("getRecord")) {
					const value = records.get(new URL(url).searchParams.get("rkey"));
					return value ? Response.json({ cid: "bafyrecord", value }) : Response.json({ error: "RecordNotFound" }, { status: 400 });
				}
				return new Response(new Uint8Array([0, 97, 115, 109]));
			},
		},
	};
	const publish = async (calls) => {
		const value = { abi: "emdash-wasm-json-v1", module: { ref: { $link: blob } }, actions: [], calls };
		const pin = await modulePin({ module: new Uint8Array([0, 97, 115, 109]), calls });
		records.set(`m.${pin.slice(0, 32)}`, value).set("m", value);
		return pin;
	};
	const pin = await publish(["a.b.c"]);
	const manifest = { instances: [{ name: "a", module: URI, pin }] };
	await publish(["x.y.z"]);
	assert.deepEqual((await loadModule(ctx, URI)).calls, ["x.y.z"], "unpinned: the latest");
	const { modules } = await loadComposition(ctx, manifest);
	assert.deepEqual([modules.a.calls, modules.a.id], [["a.b.c"], URI], "pinned: its version, its id the module's");
	assert.deepEqual((await loadModule(ctx, `did:plc:pub/m@${pin.slice(0, 32)}`)).calls, ["a.b.c"]);
	await assert.rejects(loadModule(ctx, URI, "0".repeat(64)), new RegExp(`${URI}: pin 0{64} not published \\(${URI}\\.0{32} not found\\)`));
});