Bifrost/tests/epiphany-operator-status-v2.test.mjs
2026-07-19 22:54:44 +01:00

28 lines
6.3 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { readFile,mkdtemp } from "node:fs/promises";
import { tmpdir } from "node:os";
import { resolve } from "node:path";
import { createRequire } from "node:module";
import { signPurpose,trustAnchor } from "../tools/bifrost-signed-identity.mjs";
import { enrollOperatorIdentity } from "../tools/epiphany-operator-commands.mjs";
import { EPIPHANY_RESULT_SIGNING_PURPOSE,verifySealedReceipt } from "../tools/epiphany-operator-cultnet-rudp.mjs";
import { parseOperatorResult,parseOperatorStatusV2,resultReceiptTuple } from "../tools/epiphany-operator-command-documents.mjs";
const requireCult=createRequire(resolve("..","CultLib","packages","cultnet-ts","package.json"));
const msgpack=requireCult("@msgpack/msgpack");
const fixtureRoot=process.env.EPIPHANY_OPERATOR_RUST_FIXTURE??resolve("..","EpiphanyAgent",".epiphany-smoke","operator-command-interop-rust");
async function golden(){const fixture=JSON.parse(await readFile(resolve(fixtureRoot,"protocol.json"),"utf8")).operatorStatusV2MigrationFixture;if(fixture)return fixture;const unavailable=(daemonId,healthContract)=>({daemonId,healthContract,availability:"unavailable",unavailableReason:"required-provider-record-missing",state:null,reasonCode:null,providerObservedAtUnixMillis:null,evaluatedAtUnixMillis:null,expiresAtUnixMillis:null,releaseId:null,releaseWitnessSha256:null,sourceCommit:null,deploymentId:null,projectionSha256:null});return {schemaVersion:"epiphany.operator.status.v2",releaseId:"release-fixture",releaseWitnessSha256:`sha256-${"a".repeat(64)}`,sourceCommit:"b".repeat(40),deploymentId:"deployment-fixture",coordinatorSnapshot:"coordinator-snapshot/sleeping",coordinatorState:"coordinator-state/ready",coordinatorAction:"coordinator-action/none",brakeStatus:"engaged",residentStatus:"resident-self/idle",pressureCount:0,pendingReviewCount:0,providerSetStatus:"incomplete",providers:[unavailable("yggdrasil-epiphany","epiphany.cultnet-rudp-runtime-health"),unavailable("yggdrasil-bifrost-persona-feedback","bifrost.cultnet-rudp-persona-feedback-health")],privateStateExposed:false};}
function admission(){return {schemaName:"bifrost.operator_command.delivery",schemaVersion:"bifrost.operator_command.delivery.v1",admissionId:"admission-status",packet:{commandId:"command-status",nonce:"nonce",sourceEventId:"event",sourceActorId:"actor",discordGuildId:"guild",discordChannelId:"ops",discordMessageId:"message",targetRuntimeId:"epiphany-yggdrasil",issuedAt:"2026-07-19T12:00:00Z",expiresAt:"2026-07-19T12:01:00Z",command:{kind:"status"}},packetSha256:`sha256-${"1".repeat(64)}`,sourceObserverId:"voidbot",sourceObserverRuntimeId:"voidbot-yggdrasil",provider:"bifrost",bifrostAdmissionReceiptId:"receipt",authority:"exact_operator_command_only",providerIdentityId:"bifrost",providerSignature:new Uint8Array(64)};}
async function sealed(statusV2){
const a=admission(),root=await mkdtemp(resolve(tmpdir(),"bifrost-status-v2-")),identity=await enrollOperatorIdentity(resolve(root,"executor.seed"));
const result={schemaVersion:"epiphany.operator_command.status_result.v2",resultId:"result-status",commandId:a.packet.commandId,packetSha256:a.packetSha256,targetRuntimeId:a.packet.targetRuntimeId,disposition:"observed",consequenceKind:"operator-snapshot",consequenceRef:"snapshot",completedAt:"2026-07-19T12:00:01Z",privateStateExposed:false,operatorStatus:"sleeping",stateStatus:"ready",coordinatorAction:"none",brakeStatus:"engaged",detail:"bounded",reviews:[],reviewCandidateId:"",reviewDecision:"",statusV2};
const receipt={schemaVersion:"epiphany.operator_command.sealed_result.v1",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,receipt};
}
test("exactly parses the Rust Status-v2 golden and preserves partial providers",async()=>{const value=await golden();assert.deepEqual(parseOperatorStatusV2(structuredClone(value)),value);const partial=structuredClone(value),p=partial.providers[0];Object.assign(p,{availability:"authenticated-current",unavailableReason:"",state:"healthy",reasonCode:"ok",providerObservedAtUnixMillis:1,evaluatedAtUnixMillis:2,expiresAtUnixMillis:3,releaseId:value.releaseId,releaseWitnessSha256:value.releaseWitnessSha256,sourceCommit:value.sourceCommit,deploymentId:value.deploymentId,projectionSha256:`sha256-${"3".repeat(64)}`});assert.equal(parseOperatorStatusV2(partial).providerSetStatus,"incomplete");});
test("rejects extra, missing, private, overlong, reordered, and false-complete Status-v2 shapes",async()=>{const value=await golden(),cases=[{...value,privateKey:"x"},(()=>{const x=structuredClone(value);delete x.residentStatus;return x;})(),{...value,privateStateExposed:true},{...value,residentStatus:"x".repeat(257)},{...value,providers:[...value.providers].reverse()},{...value,providerSetStatus:"complete-authenticated"}];for(const hostile of cases)assert.throws(()=>parseOperatorStatusV2(hostile));});
test("verifies the signed Status-v2 receipt and rejects nested mutation",async()=>{const built=await sealed(await golden()),trusted=trustAnchor(built.identity,"2026-07-19T11:00:00Z");assert.equal(verifySealedReceipt({receipt:built.receipt,admission:built.a,trustedIdentity:trusted,encode:msgpack.encode}),built.receipt);const mutated=structuredClone(built.receipt);mutated.result.statusV2.pressureCount++;assert.throws(()=>verifySealedReceipt({receipt:mutated,admission:built.a,trustedIdentity:trusted,encode:msgpack.encode}),/digest|signature/);});
test("non-Status v1 remains exact and cannot smuggle statusV2",()=>{const result={schemaVersion:"epiphany.operator_command.result.v1",resultId:"r",commandId:"c",packetSha256:"p",targetRuntimeId:"t",disposition:"observed",consequenceKind:"snapshot",consequenceRef:"",completedAt:"2026-07-19T12:00:01Z",privateStateExposed:false,operatorStatus:"",stateStatus:"",coordinatorAction:"",brakeStatus:"",detail:"",reviews:[],reviewCandidateId:"",reviewDecision:"",statusV2:{}};assert.throws(()=>parseOperatorResult(result),/unknown or missing/);});