// node --test javascript/src/compose/hooks.test.mjs (needs `cargo wasm`; no network) // Hooks: declared hooks checked at load, routed to instances, handlers or a default, ANDed // for combine all-allow; and the same hooks in a run with no composition (runModule). import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import { test } from "node:test"; import { modulePin, runModule, transportName, unservedHook } from "../run-module/index.js"; import { loadComposition, runCompose, staged } from "./index.js"; const wasm = new Uint8Array(await readFile(new URL("../../../target/wasm32-unknown-unknown/release/compose.wasm", import.meta.url))); const spec = JSON.parse(await readFile(new URL("../../../examples/rust/compose/module.json", import.meta.url), "utf8")); const H = "com.example.hooks.check"; const exportsOf = new Map(); const ctx = { wasm: { run: async ({ module, entry, input }) => { if (!exportsOf.has(module)) exportsOf.set(module, new WebAssembly.Instance(new WebAssembly.Module(module), {}).exports); const x = exportsOf.get(module); const data = new TextEncoder().encode(JSON.stringify(input)); const ptr = x.alloc(data.length); new Uint8Array(x.memory.buffer, ptr, data.length).set(data); const packed = BigInt.asUintN(64, x[entry](ptr, data.length)); return JSON.parse(new TextDecoder().decode(new Uint8Array(x.memory.buffer, Number(packed >> 32n), Number(packed & 0xffffffffn)))); }, }, }; // "asker" calls H (its caller entry); "even" implements H with the example's even policy entry. const modules = { asker: (hook) => ({ ...spec, calls: [], hooks: [{ nsid: H, reason: "asker checks n", ...hook }] }), even: { ...spec, calls: [], implements: [{ nsid: H, entry: "even" }] }, }; const composeWith = (hook, manifest) => loadComposition(ctx, { name: "hooks", ...manifest }, { load: async (key) => ({ ...(key === "asker" ? modules.asker(hook) : modules.even), module: wasm, id: `test:${key}` }), }); const ask = (n) => ({ nsid: H, input: { call: { input: { n } } } }); const asker = { name: "a", module: "asker" }; const route = (to, extra) => ({ from: "a", nsid: H, to, reason: `${to} must allow`, ...extra }); test("load: a required hook nothing routes, an edge the module does not declare, a hook routed twice", async () => { await assert.rejects(composeWith({ required: true }, { instances: [asker] }), /composition: instance a needs hook com.example.hooks.check \(asker checks n\): no edge routes it/); await assert.rejects(composeWith({}, { instances: [asker, { name: "p", module: "even" }], edges: [{ ...route("p"), nsid: "com.example.hooks.other" }] }), /edge a com.example.hooks.other: asker neither declares hook com.example.hooks.other nor lists it in calls/); await assert.rejects(composeWith({}, { instances: [asker, { name: "p", module: "even" }, { name: "q", module: "even" }], edges: [route("p"), route("q")] }), /routed twice/); }); test("an optional hook nothing routes answers null (skip), with no network", async () => { const comp = await composeWith({}, { instances: [asker] }); const ran = await runCompose(ctx, comp, "a", "caller", ask(3), { callFor: () => assert.fail("no network for a hook") }); assert.deepEqual(ran.result.q, { ok: true, output: null }); assert.deepEqual(ran.graph, [{ from: "a", nsid: H, hook: "unrouted", ok: true }]); }); test("all-allow: an instance and a caller handler, in edge order, the first deny wins", async () => { const comp = await composeWith({ combine: "all-allow" }, { instances: [asker, { name: "p", module: "even" }], handlers: [{ name: "judge" }], edges: [route("p"), { from: "a", nsid: H, handler: "judge", reason: "the caller must allow" }], }); const seen = []; const run = (n, verdict) => runCompose(ctx, comp, "a", "caller", ask(n), { handlers: { judge: async (input) => (seen.push(input.call.input.n), verdict) } }); assert.deepEqual((await run(4, { allow: true, violations: [] })).result.q.output, { allow: true, violations: [] }); assert.deepEqual((await run(4, { allow: false, violations: [{ msg: "not today", policyId: "judge" }] })).result.q.output, { allow: false, violations: [{ msg: "not today", policyId: "judge" }] }); // a handler that answers no verdict, or throws, is a deny naming it assert.deepEqual((await run(4, "yes")).result.q.output, { allow: false, violations: [{ msg: "no verdict", policyId: "judge" }] }); const odd = await run(3, { allow: true, violations: [] }); assert.deepEqual(odd.result.q.output, { allow: false, violations: [{ msg: "n 3 is not even", policyId: "even" }] }); assert.deepEqual(seen, [4, 4, 4], "the handler is not asked after the instance denies"); assert.deepEqual(odd.graph.map((g) => [g.to ?? g.handler, g.ok]), [["p", true]]); }); test("a default serves an unrouted hook: an instance of it at its implements entry", async () => { const comp = await composeWith({ combine: "all-allow", default: "even" }, { instances: [asker] }); assert.deepEqual(comp.manifest.instances.map((i) => [i.name, i.module]), [["a", "asker"], ["a-even", "even"]]); assert.deepEqual((await runCompose(ctx, comp, "a", "caller", ask(2))).result.q.output, { allow: true, violations: [] }); assert.equal((await runCompose(ctx, comp, "a", "caller", ask(5))).result.q.output.allow, false); // a routed hook does not get its default const routed = await composeWith({ combine: "all-allow", default: "even" }, { instances: [asker], handlers: [{ name: "judge" }], edges: [{ from: "a", nsid: H, handler: "judge", reason: "r" }] }); assert.deepEqual(routed.manifest.instances.map((i) => i.name), ["a"]); }); test("two hooks with one default module share one instance of it, at each hook's implements entry", async () => { const H2 = "com.example.hooks.second"; const both = { ...spec, calls: [], hooks: [{ nsid: H, default: "even", reason: "r" }, { nsid: H2, default: "even", reason: "r2" }] }; const even = { ...modules.even, implements: [{ nsid: H, entry: "even" }, { nsid: H2, entry: "lookup" }] }; const asked = []; const comp = await loadComposition(ctx, { instances: [asker] }, { load: async (key) => (asked.push(key), { ...(key === "asker" ? both : even), module: wasm, id: `test:${key}` }) }); assert.deepEqual(comp.manifest.instances, [asker, { name: "a-even", module: "even" }]); assert.deepEqual(comp.manifest.edges.map((e) => [e.nsid, e.to]), [[H, "a-even"], [H2, "a-even"]]); assert.deepEqual(asked, ["asker", "even"]); assert.deepEqual((await runCompose(ctx, comp, "a", "caller", ask(2))).result.q.output, { allow: true, violations: [] }); // a user instance under the default's name is still refused await assert.rejects(loadComposition(ctx, { instances: [asker, { name: "a-even", module: "even" }] }, { load: async (key) => ({ ...(key === "asker" ? both : even), module: wasm, id: `test:${key}` }) }), /instance a-even \(the default for a's hook com.example.hooks.check\) named twice/); }); test("no composition: runModule runs a hook's default nested, answers null without one, refuses a required one at start", async () => { const mod = (hook) => ({ ...modules.asker(hook), module: wasm }); const load = async (key) => (assert.equal(key, "even"), { ...modules.even, module: wasm, id: "test:even" }); const call = () => assert.fail("hooks never reach call"); const viaDefault = await runModule(ctx, mod({ combine: "all-allow", default: "even" }), "caller", ask(3), call, { load }); assert.deepEqual(viaDefault.result.q.output, { allow: false, violations: [{ msg: "n 3 is not even", policyId: "even" }] }); const noLoader = await runModule(ctx, mod({ combine: "all-allow", default: "even" }), "caller", ask(2), call); assert.equal(noLoader.result.q.output.allow, false, "a default that cannot load is a deny"); assert.deepEqual((await runModule(ctx, mod({}), "caller", ask(2), call)).result.q, { ok: true, output: null }); const required = await runModule(ctx, mod({ required: true }), "caller", ask(2), call); assert.match(required.error, /needs hook com.example.hooks.check \(asker checks n\): run it in a composition that routes it/); }); // Review 4: defaults are the instance's own publisher's, checked like any instance, pinned with it, run on their own call. test("a default: the sibling of the instance's own ref; a user instance under its name; its own required hooks; pins", async () => { const bob = "at://did:plc:bobtest/com.fedfork.exec.wasm.module"; const asked = []; const byRef = (mods) => async (ref) => (asked.push(ref), { ...mods[ref.split("/").at(-1)], module: wasm, id: ref }); const hook = { nsid: H, combine: "all-allow", default: "even", reason: "r" }; const comp = await loadComposition(ctx, { instances: [{ name: "a", module: `${bob}/asker` }] }, { load: byRef({ asker: modules.asker(hook), even: modules.even }) }); assert.deepEqual(comp.manifest.instances[1], { name: "a-even", module: `${bob}/even` }); assert.deepEqual(asked, [`${bob}/asker`, `${bob}/even`]); const short = await loadComposition(ctx, { instances: [{ name: "a", module: "bob.example/asker" }] }, { load: byRef({ asker: modules.asker(hook), even: modules.even }) }); assert.equal(short.manifest.instances[1].module, "bob.example/even", "a / instance's default is that handle's"); await assert.rejects(composeWith(hook, { instances: [asker, { name: "a-even", module: "even" }] }), /composition: instance a-even \(the default for a's hook com.example.hooks.check\) named twice/); // the default's own required hook, for the entry the default edge reaches it at const two = { ...modules.even, hooks: [{ nsid: "com.example.hooks.two", required: true, entries: ["even"], reason: "r2" }] }; const load = (even) => async (key) => ({ ...(key === "asker" ? modules.asker(hook) : even), module: wasm, id: `test:${key}` }); await assert.rejects(loadComposition(ctx, { instances: [asker] }, { load: load(two) }), /composition: instance a-even needs hook com.example.hooks.two \(r2\): no edge routes it/); // a default that lists no calls would get them all; a pinned instance's default is not pinned const { calls, ...unlisted } = modules.even; await assert.rejects(loadComposition(ctx, { instances: [asker] }, { load: load(unlisted) }), /composition: instance a hook com.example.hooks.check: its default even lists no calls \(a hook default must\)/); const pin = await modulePin({ ...modules.asker(hook), module: wasm }); await assert.rejects(loadComposition(ctx, { instances: [{ ...asker, pin }] }, { load: load(modules.even) }), /composition: instance a is pinned, but its hook com.example.hooks.check default even is not: route the hook to a pinned instance/); // a custom loader's module is checked like a fetched one await assert.rejects(loadComposition(ctx, { instances: [asker] }, { load: async () => ({ module: wasm, hooks: [{ nsid: H }] }) }), /module hooks must be a list of \{ nsid, reason, required\?: boolean/); await assert.rejects(staged("https://site.example/")("../../x"), /a staged module is a key, not \.\.\/\.\.\/x/); }); test("no composition: a default runs on its own call (callFor), never the caller's; one listing no calls is refused", async () => { const peek = { ...modules.even, calls: ["com.example.peek"], implements: [{ nsid: H, entry: "caller" }] }; const mod = (hook) => ({ ...modules.asker(hook), module: wasm }); const load = (target) => async () => ({ ...target, module: wasm, id: "test:target" }); const call = () => assert.fail("a default never runs on the caller's call"); // the default (compose's caller entry) calls com.example.peek on the call callFor gave it const own = []; const ran = await runModule(ctx, mod({ default: "peek" }), "caller", { nsid: H, input: { nsid: "com.example.peek", input: { n: 1 } } }, call, { load: load(peek), callFor: (target) => async (nsid, request) => (own.push([target.id, nsid]), { peeked: request.input.n }), }); assert.deepEqual(ran.result.q.output.q.output, { peeked: 1 }); assert.deepEqual(own, [["test:target", "com.example.peek"]]); const { calls, ...unlisted } = modules.even; const refused = await runModule(ctx, mod({ combine: "all-allow", default: "even" }), "caller", ask(2), call, { load: load(unlisted) }); assert.deepEqual(refused.result.q.output, { allow: false, violations: [{ msg: "hook default even: its module lists no calls (a hook default must)", policyId: "even" }] }); // no loader: the Rust host's text too const bare = await runModule(ctx, mod({ combine: "all-allow", default: "even" }), "caller", ask(2), call); assert.equal(bare.result.q.output.violations[0].msg, "hook default even: no loader for a module loaded from bytes (pass the host's load option)"); }); test("host pseudo-calls: a com.fedfork.exec.* hook in calls is the host's; no provides is none", async () => { const IROH = "com.fedfork.exec.iroh.connect"; const transport = { nsid: IROH, required: true, reason: "dials" }; assert.equal(unservedHook(transport, [IROH], undefined), "this host was built without iroh"); assert.equal(unservedHook(transport, [IROH], [IROH]), undefined); // not only transports: code mode's MCP server is a host pseudo-call too const MCP = "com.fedfork.exec.mcp.message"; const mcp = { nsid: MCP, required: true, reason: "runs code" }; assert.equal(unservedHook(mcp, [MCP], undefined), `this host was built without ${MCP}`); assert.equal(unservedHook(mcp, [MCP], [MCP]), undefined); assert.equal(unservedHook(mcp, [], [MCP]), "no edge routes it", "not in calls: only a route serves it"); assert.equal(unservedHook({ nsid: "com.example.foo", required: true, reason: "r" }, ["com.example.foo"], ["com.example.foo"]), "no edge routes it"); assert.equal(transportName(IROH), "iroh"); assert.equal(transportName("com.fedfork.exec.attest"), undefined); // an unrouted hook on an XRPC method in calls answers null, never the network const comp = await loadComposition(ctx, { instances: [asker] }, { load: async () => ({ ...modules.asker({}), calls: [H], module: wasm }) }); const ran = await runCompose(ctx, comp, "a", "caller", ask(3), { callFor: () => assert.fail("no network for a hook") }); assert.deepEqual(ran.result.q, { ok: true, output: null }); }); test("a routed hook cannot be subscribed to, all-allow or not (refused before any route runs)", async () => { const comp = await composeWith({ combine: "all-allow" }, { instances: [asker, { name: "p", module: "even" }], edges: [route("p")] }); const seen = []; const subscriber = { wasm: { run: async ({ input }) => { if (input.event.type === "start") return { calls: [{ id: "s", nsid: H, subscribe: true }] }; seen.push(input.event); return { done: true, result: input.event.error ?? null }; }, }, }; const ran = await runCompose(subscriber, comp, "a", "caller", {}); assert.equal(ran.result, `${H} is routed in this composition: no proxy, service or subscribe`); assert.deepEqual(ran.graph, []); });