24 lines
7.6 KiB
JavaScript
24 lines
7.6 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { createHash } from "node:crypto";
|
|
import { EventEmitter } from "node:events";
|
|
import { createSocket } from "node:dgram";
|
|
import { createRequire } from "node:module";
|
|
import { resolve } from "node:path";
|
|
import { mkdtemp } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { enrollOperatorIdentity } from "../tools/epiphany-operator-commands.mjs";
|
|
import { resultReceiptTuple } from "../tools/epiphany-operator-command-documents.mjs";
|
|
import { LEGACY_EPIPHANY_RESULT_SIGNING_PURPOSE as EPIPHANY_RESULT_SIGNING_PURPOSE,EpiphanyOperatorCultNetRudpTransport,verifySealedReceipt } from "../tools/epiphany-operator-cultnet-rudp.mjs";
|
|
import { signPurpose,trustAnchor } from "../tools/bifrost-signed-identity.mjs";
|
|
|
|
const cultLibRoot=process.env.VOIDBOT_CULTLIB_ROOT||"E:/Projects/CultLib",requireCult=createRequire(resolve(cultLibRoot,"packages/cultnet-ts/package.json"));
|
|
const msgpack=requireCult("@msgpack/msgpack"),cultnet=requireCult("cultnet-ts");
|
|
function admission(){return {schemaName:"bifrost.operator_command.delivery",schemaVersion:"bifrost.operator_command.delivery.v0",admissionId:"admission-1",packet:{commandId:"command-1",nonce:"nonce-1",sourceEventId:"event-1",sourceActorId:"actor",discordGuildId:"guild",discordChannelId:"ops",discordMessageId:"message-1",targetRuntimeId:"epiphany-yggdrasil",issuedAt:"2026-07-19T12:00:00Z",expiresAt:"2026-07-19T12:01:00Z",command:{kind:"status"}},packetSha256:"sha256-packet",sourceObserverId:"voidbot",sourceObserverRuntimeId:"voidbot-yggdrasil",provider:"bifrost",bifrostAdmissionReceiptId:"receipt-1",authority:"exact_operator_command_only",providerIdentityId:"bifrost",providerSignature:new Uint8Array(64)};}
|
|
async function fixture(){const root=await mkdtemp(resolve(tmpdir(),"epiphany-result-")),identity=await enrollOperatorIdentity(resolve(root,"executor.seed")),anchor=trustAnchor(identity,"2026-07-19T11:00:00Z"),a=admission();const result={schemaVersion:"epiphany.operator_command.result.v0",resultId:"result-1",commandId:a.packet.commandId,packetSha256:a.packetSha256,targetRuntimeId:a.packet.targetRuntimeId,disposition:"observed",consequenceKind:"operator-snapshot",consequenceRef:"snapshot-1",completedAt:"2026-07-19T12:00:01Z",privateStateExposed:false,operatorStatus:"sleeping",stateStatus:"ready",coordinatorAction:"",brakeStatus:"engaged",detail:"bounded"};const receipt={schemaVersion:"epiphany.operator_command.sealed_result.v0",result,resultPayloadSha256:`sha256-${createHash("sha256").update(msgpack.encode(result)).digest("hex")}`,commandId:result.commandId,packetSha256:result.packetSha256,targetRuntimeId:result.targetRuntimeId,completedAt:result.completedAt,providerIdentityId:identity.identityId,privateStateExposed:false,executorSignature:new Uint8Array()};receipt.executorSignature=new Uint8Array(signPurpose(identity,EPIPHANY_RESULT_SIGNING_PURPOSE,msgpack.encode(resultReceiptTuple(receipt))));return {a,identity,anchor,receipt};}
|
|
|
|
test("verifies the exact host-sealed Epiphany receipt",async()=>{const {a,anchor,receipt}=await fixture();assert.equal(verifySealedReceipt({receipt,admission:a,trustedIdentity:anchor,encode:msgpack.encode}),receipt);});
|
|
test("refuses wrong key, signature, digest, binding, predating completion, and schema",async()=>{const {a,anchor,receipt}=await fixture(),other=await fixture();const cases=[{...receipt,providerIdentityId:other.identity.identityId},{...receipt,executorSignature:new Uint8Array(64)},{...receipt,resultPayloadSha256:"sha256-wrong"},{...receipt,packetSha256:"sha256-wrong"},{...receipt,completedAt:"2026-07-19T11:59:59Z",result:{...receipt.result,completedAt:"2026-07-19T11:59:59Z"}},{...receipt,schemaVersion:"epiphany.operator_command.sealed_result.v9"}];for(const value of cases)assert.throws(()=>verifySealedReceipt({receipt:value,admission:a,trustedIdentity:anchor,encode:msgpack.encode}));});
|
|
test("accepts a correctly signed post-expiry receipt for durable exact recovery",async()=>{const {a,anchor,identity,receipt}=await fixture(),completedAt="2026-07-19T12:02:00Z",result={...receipt.result,completedAt},recovered={...receipt,result,completedAt,resultPayloadSha256:`sha256-${createHash("sha256").update(msgpack.encode(result)).digest("hex")}`,executorSignature:new Uint8Array()};recovered.executorSignature=new Uint8Array(signPurpose(identity,EPIPHANY_RESULT_SIGNING_PURPOSE,msgpack.encode(resultReceiptTuple(recovered))));assert.equal(verifySealedReceipt({receipt:recovered,admission:a,trustedIdentity:anchor,encode:msgpack.encode}),recovered);});
|
|
test("RUDP adapter requires a correlated typed application result and times out otherwise",async()=>{const {a,anchor,receipt}=await fixture();class FakeConnection extends EventEmitter{connected=false;connect(){this.connected=true;}send(){if(this.reply)setImmediate(()=>this.emit("frame",this.reply));}close(){this.closed=true;}}const fakeSocket=()=>{const s=new EventEmitter();s.bind=()=>setImmediate(()=>s.emit("listening"));return s;};const make=(reply,timeoutMs=100)=>{const connection=new FakeConnection();connection.reply=reply;return {connection,transport:new EpiphanyOperatorCultNetRudpTransport({endpoint:"rudp://127.0.0.1:49100",trustedEpiphanyIdentity:anchor,timeoutMs,cultnetRuntime:cultnet,msgpackRuntime:msgpack,socketFactory:fakeSocket,connectionFactory:()=>connection})};};const message={schemaVersion:"cultnet.document_put_raw.v0",messageId:"operator-result-command-1",document:{schemaId:"epiphany.operator_command.sealed_result",recordKey:a.packet.commandId,storedAt:receipt.completedAt,payloadEncoding:"messagepack",payload:msgpack.encode(receipt),sourceRuntimeId:a.packet.targetRuntimeId,sourceAgentId:receipt.providerIdentityId,sourceRole:"epiphany-operator-command-executor",tags:["cultnet.transport.rudp.v0"]}};const ok=make({channelId:"schema",payload:msgpack.encode(message)});assert.equal((await ok.transport.execute(a)).result.resultId,"result-1");const absent=make(undefined);await assert.rejects(()=>absent.transport.execute(a),/Timed out waiting for the correlated/);const wrong=make({channelId:"schema",payload:msgpack.encode({...message,document:{...message.document,recordKey:"alien"}})});await assert.rejects(()=>wrong.transport.execute(a),/substituted result authority/);});
|
|
test("real CultNet RUDP socket path waits for the sealed application document",async()=>{const {a,anchor,receipt}=await fixture(),socket=createSocket("udp4");await new Promise((ok,fail)=>{socket.once("error",fail);socket.bind(0,"127.0.0.1",ok)});const server=new cultnet.CultNetRudpSocketTransportConnection({runtimeId:a.packet.targetRuntimeId,socket,mode:"server",connectionId:0xe91f0001,resendDelayMs:25,resendPollMs:5});server.on("frame",frame=>{const request=msgpack.decode(frame.payload);assert.equal(request.document.schemaId,"bifrost.operator_command.delivery");const response={schemaVersion:"cultnet.document_put_raw.v0",messageId:"operator-result-command-1",document:{schemaId:"epiphany.operator_command.sealed_result",recordKey:a.packet.commandId,storedAt:receipt.completedAt,payloadEncoding:"messagepack",payload:msgpack.encode(receipt),sourceRuntimeId:a.packet.targetRuntimeId,sourceAgentId:receipt.providerIdentityId,sourceRole:"epiphany-operator-command-executor",tags:["cultnet.transport.rudp.v0"]}};server.send("schema",msgpack.encode(cultnet.encodeCultNetMessageForWire(response,"cultnet.schema.v0")));});try{const port=socket.address().port,transport=new EpiphanyOperatorCultNetRudpTransport({endpoint:`rudp://127.0.0.1:${port}`,trustedEpiphanyIdentity:anchor,timeoutMs:1000,cultnetRuntime:cultnet,msgpackRuntime:msgpack});const output=await transport.execute(a);assert.equal(output.receipt.providerIdentityId,anchor.identityId);assert.equal(output.result.commandId,a.packet.commandId);}finally{server.close();}});
|