Bifrost/tests/epiphany-operator-command.test.mjs
2026-07-19 12:00:50 +01:00

14 lines
4.6 KiB
JavaScript

import test from "node:test";import assert from "node:assert/strict";import {mkdtemp} from "node:fs/promises";import {tmpdir} from "node:os";import {resolve} from "node:path";import {createRequire} from "node:module";
import {admitOperatorRequest,enrollOperatorIdentity,ImmutableOperatorLedger,OPERATOR_SIGNING_PURPOSE} from "../tools/epiphany-operator-commands.mjs";
import {admissionTuple,packetTuple,parseOperatorRequest} from "../tools/epiphany-operator-command-documents.mjs";
import {verifyPurpose} from "../tools/bifrost-signed-identity.mjs";
const requireCult=createRequire(resolve("E:/Projects/CultLib/packages/cultnet-ts/package.json")),{encode}=requireCult("@msgpack/msgpack");
const actorLink={guildId:"guild",discordAuthorId:"owner",bifrostActorId:"actor",heimdallActorRef:"heimdall:actor:1"};
function request(command={kind:"status"}){return {schemaName:"voidbot.discord.epiphany_operator_request",schemaVersion:"voidbot.discord.epiphany_operator_request.v0",requestId:"interaction-1",commandId:"interaction-1",nonce:"interaction-1",sourceEventId:"interaction-1",sourceActorDiscordId:"owner",discordGuildId:"guild",discordChannelId:"channel",discordMessageId:"interaction-1",targetRuntimeId:"epiphany-yggdrasil",issuedAt:"2026-07-19T10:00:00.000Z",expiresAt:"2026-07-19T10:00:30.000Z",producerId:"voidbot",producerRuntimeId:"voidbot-yggdrasil",authorityClass:"operator_request_only",status:"pending",command};}
function result(admission){return {providerIdentityId:"epiphany-host",result:{schemaVersion:"epiphany.operator_command.result.v0",resultId:"result-1",commandId:admission.packet.commandId,packetSha256:admission.packetSha256,targetRuntimeId:admission.packet.targetRuntimeId,disposition:"observed",consequenceKind:"operator-snapshot",consequenceRef:"snapshot-1",completedAt:"2026-07-19T10:00:01.000Z",privateStateExposed:false,operatorStatus:"sleeping",stateStatus:"ready",coordinatorAction:"",brakeStatus:"engaged",detail:"bounded"}};}
async function identity(){const d=await mkdtemp(resolve(tmpdir(),"bifrost-operator-"));return enrollOperatorIdentity(resolve(d,"operator.seed"));}
test("signs the exact Rust packet and admission tuples",async()=>{const id=await identity(),out=await admitOperatorRequest({request:request(),ownerDiscordId:"owner",actorLink,identity:id,encode,expectedEpiphanyIdentityId:"epiphany-host",now:new Date("2026-07-19T10:00:01Z"),transport:{execute:async a=>result(a)}});assert.equal(out.admission.packetSha256,`sha256-${(await import("node:crypto")).createHash("sha256").update(encode(packetTuple(out.admission.packet))).digest("hex")}`);assert.ok(verifyPurpose(id.publicKey,OPERATOR_SIGNING_PURPOSE,encode(admissionTuple(out.admission)),out.admission.providerSignature));assert.equal(out.result.disposition,"observed");});
test("requires exact owner and linked Heimdall actor",async()=>{const id=await identity();for(const args of [{ownerDiscordId:"other",actorLink},{ownerDiscordId:"owner",actorLink:null},{ownerDiscordId:"owner",actorLink:{...actorLink,heimdallActorRef:""}}])await assert.rejects(()=>admitOperatorRequest({request:request(),identity:id,encode,expectedEpiphanyIdentityId:"epiphany-host",now:new Date("2026-07-19T10:00:01Z"),transport:{execute:async a=>result(a)},...args}));});
test("strict request, ttl, command bounds, and expiry fail closed",()=>{assert.throws(()=>parseOperatorRequest({...request(),extra:true}));assert.throws(()=>parseOperatorRequest({...request(),expiresAt:"2026-07-19T10:01:01Z"}));assert.throws(()=>parseOperatorRequest(request({kind:"argv",args:["whoami"]})));assert.throws(()=>parseOperatorRequest(request({kind:"sleep",reason:""})));});
test("does not synthesize success without an authenticated transport result",async()=>{const id=await identity(),base={request:request(),ownerDiscordId:"owner",actorLink,identity:id,encode,expectedEpiphanyIdentityId:"epiphany-host",now:new Date("2026-07-19T10:00:01Z")};await assert.rejects(()=>admitOperatorRequest(base),/live CultNet RUDP adapter is missing/);await assert.rejects(()=>admitOperatorRequest({...base,transport:{execute:async a=>({...result(a),providerIdentityId:"impostor"})}}),/authenticated Epiphany/);await assert.rejects(()=>admitOperatorRequest({...base,transport:{execute:async a=>({...result(a),result:{...result(a).result,packetSha256:"sha256-wrong"}})}}),/not bound/);});
test("immutable ledger rejects request and result collisions",()=>{const ledger=new ImmutableOperatorLedger(),r=request(),a={x:1};ledger.admit(r.requestId,r,a);assert.throws(()=>ledger.admit(r.requestId,{...r,nonce:"different"},a),/collision/);ledger.complete(r.requestId,{x:1},"epiphany");assert.throws(()=>ledger.complete(r.requestId,{x:2},"epiphany"),/collision/);});