Files
MikrotikManager/backend/src/services/server-probe-retired-source.test.ts
T

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})
}
})