78 lines
5.0 KiB
TypeScript
78 lines
5.0 KiB
TypeScript
import assert from "node:assert/strict"
|
|
import { findRetiredServerProbeHistory } from "./server-probe-retired-history.js"
|
|
import { randomUUID } from "node:crypto"
|
|
import { mkdtemp,rm } from "node:fs/promises"
|
|
import { tmpdir } from "node:os"
|
|
import path from "node:path"
|
|
import { test } from "node:test"
|
|
import { serverProbeRetiredFixture as fixture } from "./server-probe-retired-source.fixture.js"
|
|
import { createServerProbeJournalHistoryReader } from "./server-probe-journal-history.js"
|
|
import { openServerProbeRetiredSource,projectServerProbeRetiredSource,ServerProbeRetirementSourceRefused } from "./server-probe-retired-source.js"
|
|
|
|
test("production proofs authenticate the minimal projection and keep the original payload readable only with the current fence",async()=>{
|
|
const directory=await mkdtemp(path.join(tmpdir(),"owned-probe-retirement-"))
|
|
const previous=process.env.MCP_STATE_DIR
|
|
process.env.MCP_STATE_DIR=directory
|
|
try{
|
|
for(const twoSides of [false,true]){
|
|
const {raw,context,receipt,serverIds}=await fixture(twoSides)
|
|
const exact=structuredClone(raw),signed=await projectServerProbeRetiredSource(raw)
|
|
assert.deepEqual(raw,exact)
|
|
const opened=await openServerProbeRetiredSource(JSON.parse(JSON.stringify(signed)))
|
|
assert.deepEqual(opened,signed.source)
|
|
assert.deepEqual(opened.serverIds,serverIds)
|
|
assert.equal(opened.authorityExpiresAt,"2025-01-02T00:00:15.000000Z")
|
|
assert.equal(opened.terminalAt,"2025-01-02T00:00:16.000000Z")
|
|
assert.equal(opened.activityAt,opened.terminalAt)
|
|
assert.equal(opened.retentionDays,365)
|
|
assert.equal(opened.gcNotBefore,"2026-01-02T00:01:15.000000Z")
|
|
const lookup={operationId:opened.executionId,receiptId:opened.receiptId,connectionId:opened.connectionId,ownerId:opened.ownerId,scopeServerIds:serverIds}
|
|
const stored={...signed,...raw.anchor,plan_id:raw.original.plan_id,tombstone_server_ids:serverIds.map(String),
|
|
retention_days:raw.admission.retention_days,safety_ms:raw.admission.safety_ms,
|
|
gc_not_before:raw.admission.gc_not_before.replace("Z","000Z"),authority_expires_at:raw.anchor.authority_expires_at.replace("Z","000Z"),
|
|
payload_purged:false,payload_proof:raw.payload.receipt_proof,payload_sha256:opened.ciphertextSha256}
|
|
const read=(row:Record<string,unknown>)=>findRetiredServerProbeHistory(async (_sql,values)=>{
|
|
assert.deepEqual(values,[lookup.receiptId,lookup.operationId,lookup.connectionId,lookup.ownerId,lookup.scopeServerIds])
|
|
return [row]
|
|
},lookup)
|
|
assert.deepEqual(await read(stored),{source:opened,payloadPurged:false})
|
|
assert.deepEqual(await read({...stored,payload_purged:true,payload_proof:null,payload_sha256:null}),{source:opened,payloadPurged:true})
|
|
for(const alteration of [{tombstone_server_ids:["800"]},{plan_id:randomUUID()},{gc_not_before:raw.admission.authority_expires_at},
|
|
{mcp_credential_id:randomUUID()},{payload_sha256:"d".repeat(64)},{payload_purged:true}])
|
|
assert.equal(await read({...stored,...alteration}),undefined)
|
|
assert.equal(await read({...stored,proof:"d".repeat(64)}),undefined)
|
|
const envelope=JSON.stringify(signed)
|
|
for(const secret of [raw.payload.receipt_ciphertext,raw.original.evidence.sealed,receipt.output!,"inert-private-inner-binding"])
|
|
assert(!envelope.includes(secret))
|
|
let permitted=true
|
|
const reader=createServerProbeJournalHistoryReader({
|
|
assertReadAuthority:async()=>{if(!permitted)throw Error("current scope or protection denied")},
|
|
loadArchive:async()=>[{...raw.anchor,receipt_ciphertext:raw.payload.receipt_ciphertext,quarantine_count:0}],
|
|
})
|
|
const binding={context,receiptId:opened.receiptId,bindingProof:opened.bindingProof}
|
|
assert.deepEqual(await reader.read(binding),receipt)
|
|
permitted=false
|
|
await assert.rejects(reader.read(binding),/current scope or protection denied/)
|
|
for(const alteration of [{retentionDays:364},{activityAt:"2025-01-02T00:00:17.000000Z"},{ownerId:randomUUID()}])
|
|
await assert.rejects(openServerProbeRetiredSource({...signed,source:{...signed.source,...alteration}}),ServerProbeRetirementSourceRefused)
|
|
}
|
|
const {raw}=await fixture()
|
|
for(const alter of [
|
|
(copy:typeof raw)=>{copy.original.evidence.sealed="broken"},
|
|
(copy:typeof raw)=>{copy.payload.receipt_proof="b".repeat(64)},
|
|
(copy:typeof raw)=>{copy.original.step_result.sha256="b".repeat(64)},
|
|
(copy:typeof raw)=>{copy.stages[0].received_at="2025-01-02T00:00:00.000001Z"},
|
|
(copy:typeof raw)=>{copy.admission.authority_expires_at="2025-01-02T00:00:15.000001Z"},
|
|
(copy:typeof raw)=>{copy.quarantineCount=1},
|
|
(copy:typeof raw)=>{copy.cancellationCount=1},
|
|
]){
|
|
const copy=structuredClone(raw);alter(copy)
|
|
await assert.rejects(projectServerProbeRetiredSource(copy),ServerProbeRetirementSourceRefused)
|
|
}
|
|
}finally{
|
|
if(previous===undefined)delete process.env.MCP_STATE_DIR
|
|
else process.env.MCP_STATE_DIR=previous
|
|
await rm(directory,{recursive:true,force:true})
|
|
}
|
|
})
|