Bifrost/tests/persona-discord-delivery.test.mjs
Meta Vens 868df35449 Bifrost suite: load @gamecult/cultcache-ts; skip Rust fixture tests with a stated reason
CultLib 8cb3b728 renamed only cultcache-ts to @gamecult/cultcache-ts; the
suite and three tools still required the bare name. Rename the require
string in tests/persona-feedback-cli, persona-discord-delivery,
persona-discord-crossing-rust-smoke, tools/persona-feedback (:114),
agent-transport and governance-threads. No fallback: a pre-8cb3b728 CultLib
fails loudly at import. operator-notification.mjs is untouched (retire cut).

The two Rust fixture tests skip, naming the missing producer (Epiphany
removed both fixture bins in 387afe49), and drop the hard-coded
CARGO_TARGET_DIR override. Builds.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 17:16:39 +02:00

36 lines
16 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import {createHash} from "node:crypto";
import {createRequire} from "node:module";
import {mkdtemp,writeFile} from "node:fs/promises";
import {tmpdir} from "node:os";
import {resolve} from "node:path";
import {buildPersonaDiscordDeliveryDefinitions,executionSchema,parseReceipt,parseRequest,receiptDocumentTuple,receiptIdentityDomain,receiptSignatureDomain,receiptSigningPurpose,receiptSigningTuple,requestIdentityDomain,requestSignatureDomain,requestSigningPurpose,requestSigningTuple} from "../tools/persona-discord-delivery-documents.mjs";
import {enrollPersonaDiscordDeliveryIdentity,exportPersonaDiscordPermitRequestAnchor,inspectPersonaDiscordDeliveryReadiness,processPersonaDiscordDeliveries} from "../tools/persona-discord-delivery.mjs";
import {enrollDomainIdentity,signDomainPurpose,verifyDomainPurpose} from "../tools/bifrost-signed-identity.mjs";
const signature=()=>new Uint8Array(64);
const request=()=>({schemaVersion:"epiphany.persona_discord_delivery_request.v0",requestId:"request-1",effectDocumentId:"effect-1",targetRuntimeId:"epiphany-yggdrasil",personaAgentId:"epiphany.Persona",channelId:"123",replyToMessageId:"456",content:"hello",contentSha256:`sha256-${"a".repeat(64)}`,issuedAt:"2026-07-21T12:00:00Z",expiresAt:"2026-07-21T12:01:00Z",privateStateExposed:false,signerIdentityId:"signer",signerSignature:signature()});
test("Persona delivery request has one exact signature tuple",()=>{const value=parseRequest(request());assert.deepEqual(requestSigningTuple(value),["epiphany.persona_discord_delivery_request.v0","request-1","effect-1","epiphany-yggdrasil","epiphany.Persona","123","456","hello",`sha256-${"a".repeat(64)}`,"2026-07-21T12:00:00Z","2026-07-21T12:01:00Z",false,"signer"]);});
test("Persona delivery receipt terminal states cannot counterfeit delivery",()=>{const base={schemaVersion:"bifrost.persona_discord_delivery_receipt.v0",receiptId:"request-1",requestId:"request-1",requestPayloadSha256:`sha256-${"b".repeat(64)}`,status:"unknown",channelId:"123",replyToMessageId:"456",messageId:"",transport:"",crossingReceiptId:"",receiptUrl:"",completedAt:"2026-07-21T12:00:02Z",providerIdentityId:"bifrost",privateStateExposed:false,providerSignature:signature()};assert.equal(receiptSigningTuple(parseReceipt(base)).length,14);assert.equal(receiptDocumentTuple(base).length,15);assert.deepEqual(parseReceipt(receiptDocumentTuple(base)),base);assert.throws(()=>parseReceipt({...base,messageId:"counterfeit"}),/may not claim delivery evidence/);assert.doesNotThrow(()=>parseReceipt({...base,status:"failed"}));assert.doesNotThrow(()=>parseReceipt({...base,status:"completed",messageId:"789",transport:"bifrost.discord-post",crossingReceiptId:"crossing-1",receiptUrl:"https://discord.com/channels/g/123/789"}));});
test("Persona delivery documents refuse privacy and identity substitutions",()=>{assert.throws(()=>parseRequest({...request(),privateStateExposed:true}),/must be false/);const receipt={schemaVersion:"bifrost.persona_discord_delivery_receipt.v0",receiptId:"receipt-2",requestId:"request-1",requestPayloadSha256:`sha256-${"b".repeat(64)}`,status:"failed",channelId:"123",replyToMessageId:"",messageId:"",transport:"",crossingReceiptId:"",receiptUrl:"",completedAt:"2026-07-21T12:00:02Z",providerIdentityId:"bifrost",privateStateExposed:false,providerSignature:signature()};assert.throws(()=>parseReceipt(receipt),/must equal requestId/);});
test("receipt signer and permit requester are distinct domain identities",async()=>{const root=await mkdtemp(resolve(tmpdir(),"persona-mouth-identities-")),runtime=loadRuntime(),receiptKey=resolve(root,"receipt.seed"),permitKey=resolve(root,"permit.seed"),receiptAnchor=resolve(root,"receipt-anchor.msgpack"),permitAnchor=resolve(root,"permit-anchor.msgpack"),receipt=await enrollPersonaDiscordDeliveryIdentity({runtime,privateKeyPath:receiptKey,trustAnchorOut:receiptAnchor}),permit=await exportPersonaDiscordPermitRequestAnchor({runtime,privateKeyPath:permitKey,trustAnchorOut:permitAnchor});assert.notEqual(receiptKey,permitKey);assert.notEqual(receipt.identityId,permit.identityId);});
test("delivery listener admits absent typed stores when their owner directory is writable",async()=>{const root=await mkdtemp(resolve(tmpdir(),"persona-mouth-readiness-")),runtime=loadRuntime(),requestIdentity=await enrollDomainIdentity(resolve(root,"request.seed"),"request identity",requestIdentityDomain),mouthAnchor=resolve(root,"mouth-anchor.msgpack"),permitAnchor=resolve(root,"permit-anchor.msgpack"),receiptKey=resolve(root,"receipt.seed"),permitKey=resolve(root,"permit.seed");await writeFile(mouthAnchor,runtime.encode(requestAnchor(requestIdentity)));await writeFile(permitAnchor,new Uint8Array([1]));await enrollPersonaDiscordDeliveryIdentity({runtime,privateKeyPath:receiptKey,trustAnchorOut:resolve(root,"receipt-anchor.msgpack")});await exportPersonaDiscordPermitRequestAnchor({runtime,privateKeyPath:permitKey,trustAnchorOut:resolve(root,"permit-request-anchor.msgpack")});const readiness=await inspectPersonaDiscordDeliveryReadiness({runtime,requestStorePath:resolve(root,"requests.cc"),receiptStorePath:resolve(root,"receipts.cc"),executionStorePath:resolve(root,"executions.cc"),epiphanyTrustAnchorPath:mouthAnchor,epiphanyRuntimeId:"epiphany-yggdrasil",epiphanyPermitAnchorPath:permitAnchor,epiphanyPermitEndpoint:"rudp://127.0.0.1:9",privateKeyPath:receiptKey,permitRequesterPrivateKeyPath:permitKey});assert.equal(readiness.ready,true);assert.deepEqual(readiness.reasons,[]);});
test("Bifrost authenticates one request, publishes one signed receipt, and replays without reposting",async()=>{const root=await mkdtemp(resolve(tmpdir(),"persona-mouth-")),runtime=loadRuntime(),defs=buildPersonaDiscordDeliveryDefinitions(runtime.defineDocumentType),requestStore=resolve(root,"requests.cc"),receiptStore=resolve(root,"receipts.cc"),executionStore=resolve(root,"private","executions.cc"),requestKey=resolve(root,"request.seed"),deliveryKey=resolve(root,"delivery.seed"),anchorPath=resolve(root,"request-anchor.msgpack"),counterPath=resolve(root,"post-count"),bridgePath=resolve(root,"fake-bridge.mjs"),requestIdentity=await enrollDomainIdentity(requestKey,"request identity",requestIdentityDomain),deliveryIdentity=await enrollDomainIdentity(deliveryKey,"delivery identity",receiptIdentityDomain);await writeFile(anchorPath,runtime.encode(requestAnchor(requestIdentity)));await writeFile(bridgePath,`import{readFileSync,writeFileSync}from'node:fs';const p=${JSON.stringify(counterPath)},i=process.argv.indexOf('--cultmesh-command-id');if(i<0||process.argv[i+1]!=='request-1')process.exit(2);let n=0;try{n=Number(readFileSync(p,'utf8'))}catch{}writeFileSync(p,String(n+1));console.log(JSON.stringify({action:'discord-post',ok:true,channelId:'123',messageId:'789',transport:'bifrost.discord-post',crossingReceiptId:'crossing-1',url:'https://discord.com/channels/g/123/789'}));`);const now=Date.now(),value={...request(),issuedAt:new Date(now-1000).toISOString(),expiresAt:new Date(now+60000).toISOString(),signerIdentityId:requestIdentity.identityId};value.contentSha256=`sha256-${createHash("sha256").update(value.content).digest("hex")}`;value.signerSignature=new Uint8Array(signDomainPurpose(requestIdentity,requestSignatureDomain,requestSigningPurpose,runtime.encode(requestSigningTuple(value))));const requests=await open(runtime,defs.request,requestStore);await requests.put(defs.request,value.requestId,value);const options={runtime,requestStorePath:requestStore,receiptStorePath:receiptStore,executionStorePath:executionStore,epiphanyTrustAnchorPath:anchorPath,epiphanyRuntimeId:"epiphany-yggdrasil",privateKeyPath:deliveryKey,targetAdmitted:()=>true,bridgeCliPath:bridgePath,bifrostRoot:root,requestPermit:async()=>({permitId:"permit-1"})};let results=await processPersonaDiscordDeliveries(options);assert.equal(results[0].status,"completed");results=await processPersonaDiscordDeliveries(options);assert.equal(results.length,0);const receipts=await open(runtime,defs.receipt,receiptStore),receipt=receipts.get(defs.receipt,value.requestId);assert.equal(receipt.messageId,"789");assert.equal(verifyDomainPurpose(deliveryIdentity.publicKey,receiptSignatureDomain,receiptSigningPurpose,runtime.encode(receiptSigningTuple(receipt)),receipt.providerSignature),true);assert.equal(await import("node:fs/promises").then(fs=>fs.readFile(counterPath,"utf8")),"1");});
test("running journal recovers as terminal unknown without a second Discord post",async()=>{const root=await mkdtemp(resolve(tmpdir(),"persona-mouth-crash-")),runtime=loadRuntime(),defs=buildPersonaDiscordDeliveryDefinitions(runtime.defineDocumentType),requestStore=resolve(root,"requests.cc"),receiptStore=resolve(root,"receipts.cc"),executionStore=resolve(root,"private","executions.cc"),requestIdentity=await enrollDomainIdentity(resolve(root,"request.seed"),"request identity",requestIdentityDomain),deliveryKey=resolve(root,"delivery.seed"),anchorPath=resolve(root,"anchor.msgpack");await enrollDomainIdentity(deliveryKey,"delivery identity",receiptIdentityDomain);await writeFile(anchorPath,runtime.encode(requestAnchor(requestIdentity)));const now=Date.now(),value={...request(),issuedAt:new Date(now-1000).toISOString(),expiresAt:new Date(now+60000).toISOString(),signerIdentityId:requestIdentity.identityId};value.contentSha256=`sha256-${createHash("sha256").update(value.content).digest("hex")}`;value.signerSignature=new Uint8Array(signDomainPurpose(requestIdentity,requestSignatureDomain,requestSigningPurpose,runtime.encode(requestSigningTuple(value))));const requests=await open(runtime,defs.request,requestStore);await requests.put(defs.request,value.requestId,value);const digest=`sha256-${createHash("sha256").update(runtime.encode(requestSigningTuple(value))).digest("hex")}`,executions=await open(runtime,defs.execution,executionStore);await executions.put(defs.execution,value.requestId,{schemaName:"bifrost.persona_discord_delivery_execution",schemaVersion:executionSchema,requestId:value.requestId,requestPayloadSha256:digest,status:"running",recordedAt:new Date().toISOString(),detail:"crash fixture"});const results=await processPersonaDiscordDeliveries({runtime,requestStorePath:requestStore,receiptStorePath:receiptStore,executionStorePath:executionStore,epiphanyTrustAnchorPath:anchorPath,epiphanyRuntimeId:"epiphany-yggdrasil",privateKeyPath:deliveryKey,targetAdmitted:()=>true,bridgeCliPath:resolve(root,"must-not-run.mjs"),bifrostRoot:root});assert.equal(results[0].status,"unknown");assert.equal(results[0].messageId,"");});
test("permit intent survives network failure and restart reuses its exact request tuple",async()=>{const f=await deliveryFixture("permit-retry-");const attempts=[];let results=await processPersonaDiscordDeliveries({...f.options,requestPermit:async value=>{attempts.push({...value});throw new Error("permit network unavailable");}});assert.equal(results[0].status,"permit_pending");const executions=await open(f.runtime,f.defs.execution,f.executionStore),pending=executions.get(f.defs.execution,f.value.requestId);assert.equal(pending.status,"permit_pending");assert.equal(pending.permitNonce,attempts[0].nonce);assert.equal(pending.permitIssuedAt,attempts[0].issuedAt);assert.equal(pending.permitExpiresAt,attempts[0].expiresAt);results=await processPersonaDiscordDeliveries({...f.options,requestPermit:async value=>{attempts.push({...value});return {permitId:"permit-after-restart"};}});assert.equal(results[0].status,"completed");assert.equal(attempts.length,2);for(const key of ["requestId","requestPayloadSha256","targetRuntimeId","nonce","issuedAt","expiresAt"])assert.equal(attempts[1][key],attempts[0][key]);assert.equal(await import("node:fs/promises").then(fs=>fs.readFile(f.counterPath,"utf8")),"1");});
test("expired permit intent restarts as terminal unknown without requesting or posting",async()=>{const f=await deliveryFixture("permit-expired-"),digest=`sha256-${createHash("sha256").update(f.runtime.encode(requestSigningTuple(f.value))).digest("hex")}`,executions=await open(f.runtime,f.defs.execution,f.executionStore),issuedAt=new Date(Date.now()-6000).toISOString(),expiresAt=new Date(Date.now()-1000).toISOString();await executions.put(f.defs.execution,f.value.requestId,{schemaName:"bifrost.persona_discord_delivery_execution",schemaVersion:executionSchema,requestId:f.value.requestId,requestPayloadSha256:digest,status:"permit_pending",recordedAt:issuedAt,permitNonce:"persisted-nonce",permitIssuedAt:issuedAt,permitExpiresAt:expiresAt,detail:"restart fixture"});let permitCalls=0;const results=await processPersonaDiscordDeliveries({...f.options,requestPermit:async()=>{permitCalls++;throw new Error("must not request");},bridgeCliPath:resolve(f.root,"must-not-post.mjs")});assert.equal(results[0].status,"unknown");assert.equal(results[0].messageId,"");assert.equal(permitCalls,0);await assert.rejects(import("node:fs/promises").then(fs=>fs.readFile(f.counterPath,"utf8")));});
function loadRuntime(){const cult=resolve(import.meta.dirname,"..","..","CultLib"),cr=createRequire(resolve(cult,"packages","cultcache-ts","package.json")),nr=createRequire(resolve(cult,"packages","cultnet-ts","package.json")),cc=cr("@gamecult/cultcache-ts"),mp=nr("@msgpack/msgpack");return {CultCache:cc.CultCache,SingleFileMessagePackBackingStore:cc.SingleFileMessagePackBackingStore,defineDocumentType:cc.defineDocumentType,encode:mp.encode,decode:mp.decode};}
async function open(runtime,definition,path){const cache=runtime.CultCache.builder().withDocumentType(definition).withGenericStore(new runtime.SingleFileMessagePackBackingStore(path)).build();await cache.pullAllBackingStores();return cache;}
function requestAnchor(identity){return ["gamecult.service_trust_anchor.v1","epiphany-persona-mouth:epiphany-yggdrasil:v0","epiphany-persona-mouth","epiphany-yggdrasil",identity.identityId,new Uint8Array(identity.publicKey),"ed25519",requestSigningPurpose,"epiphany.persona_discord_delivery_request.v0","root",Date.now(),null,false];}
async function deliveryFixture(prefix){const root=await mkdtemp(resolve(tmpdir(),prefix)),runtime=loadRuntime(),defs=buildPersonaDiscordDeliveryDefinitions(runtime.defineDocumentType),requestStore=resolve(root,"requests.cc"),receiptStore=resolve(root,"receipts.cc"),executionStore=resolve(root,"private","executions.cc"),deliveryKey=resolve(root,"delivery.seed"),anchorPath=resolve(root,"request-anchor.msgpack"),counterPath=resolve(root,"post-count"),bridgeCliPath=resolve(root,"fake-bridge.mjs"),requestIdentity=await enrollDomainIdentity(resolve(root,"request.seed"),"request identity",requestIdentityDomain);await enrollDomainIdentity(deliveryKey,"delivery identity",receiptIdentityDomain);await writeFile(anchorPath,runtime.encode(requestAnchor(requestIdentity)));await writeFile(bridgeCliPath,`import{readFileSync,writeFileSync}from'node:fs';const p=${JSON.stringify(counterPath)};let n=0;try{n=Number(readFileSync(p,'utf8'))}catch{}writeFileSync(p,String(n+1));console.log(JSON.stringify({action:'discord-post',ok:true,channelId:'123',messageId:'789',transport:'bifrost.discord-post',crossingReceiptId:'crossing-1',url:'https://discord.com/channels/g/123/789'}));`);const now=Date.now(),value={...request(),issuedAt:new Date(now-1000).toISOString(),expiresAt:new Date(now+60000).toISOString(),signerIdentityId:requestIdentity.identityId};value.contentSha256=`sha256-${createHash("sha256").update(value.content).digest("hex")}`;value.signerSignature=new Uint8Array(signDomainPurpose(requestIdentity,requestSignatureDomain,requestSigningPurpose,runtime.encode(requestSigningTuple(value))));const requests=await open(runtime,defs.request,requestStore);await requests.put(defs.request,value.requestId,value);return {root,runtime,defs,value,executionStore,counterPath,options:{runtime,requestStorePath:requestStore,receiptStorePath:receiptStore,executionStorePath:executionStore,epiphanyTrustAnchorPath:anchorPath,epiphanyRuntimeId:"epiphany-yggdrasil",privateKeyPath:deliveryKey,targetAdmitted:()=>true,bridgeCliPath,bifrostRoot:root}};}