114 lines
13 KiB
TypeScript
114 lines
13 KiB
TypeScript
import assert from "node:assert/strict"
|
|
import { test } from "node:test"
|
|
import { createHmac, randomUUID } from "node:crypto"
|
|
import { createBandwidthExternalNodeRegistry, BandwidthExternalNodeRegistryError, BandwidthExternalNodeRegistryUnknown } from "./bandwidth-external-node-registry.js"
|
|
import { createBandwidthNodeRegistry } from "./bandwidth-node-registry.js"
|
|
import type { BandwidthPeerObservationEvidence } from "./bandwidth-peer-observation.js"
|
|
import type { ProbeStorageConnection } from "./server-probe-journal-maintenance.js"
|
|
|
|
type Row=Record<string,unknown>
|
|
const canonical=(v:unknown):string=>Array.isArray(v)?"["+v.map(canonical).join(",")+"]":v&&typeof v==="object"?"{"+Object.entries(v).sort(([a],[b])=>a.localeCompare(b)).map(([k,v])=>JSON.stringify(k)+":"+canonical(v)).join(",")+"}":JSON.stringify(v)
|
|
const mac=(purpose:string,value:unknown)=>createHmac("sha256","synthetic-fixed-issuer-only").update(purpose+":"+canonical(value)).digest("hex")
|
|
const installationId=randomUUID(),issuerKeySha256="a".repeat(64),quiescenceProof="b".repeat(64)
|
|
const root={installationId,issuerKeySha256,quiescenceProof}
|
|
const scope=()=>({deadlineAt:Date.now()+5000})
|
|
/** Inert SQL state machine, no pool/PG/remote imports. The same node table and
|
|
* MAC issuer are shared by the real managed and external registry functions. */
|
|
function fixture(){
|
|
const nodes:Row[]=[],aliases:Row[]=[],events:Row[]=[],managedAliases:Row[]=[],managedEvents:Row[]=[],queries:string[]=[],purposes:string[]=[]
|
|
const occupancy={status:"unknown",node_id:"never-changed"},observations=new WeakMap<object,BandwidthPeerObservationEvidence>()
|
|
let revoked=false,keyChanged=false,commitMode:"ok"|"lost"|"rows"="ok",afterEvent=false,finalSelect=false,inspectionsAfterSelect=0, revokeAtCommit=false,leaseCount=0
|
|
let onProof:((purpose:string)=>void)|undefined
|
|
const authority=()=>{if(revoked)throw Error("original grant revoked");return{...root,issuerKeySha256:keyChanged?"f".repeat(64):issuerKeySha256,authorityProof:"c".repeat(64),authorityGeneration:"original-grant",expiresAt:Date.now()+60000}}
|
|
// Stable original expiry: extending it at every check must be refused.
|
|
const expiresAt=Date.now()+60000
|
|
const authorize=async()=>({...authority(),expiresAt})
|
|
const inspect=async(token:unknown)=>{
|
|
const e=token&&typeof token==="object"?observations.get(token):undefined;if(!e)throw Error("not genuine")
|
|
if(revokeAtCommit&&finalSelect&&++inspectionsAfterSelect===3)revoked=true
|
|
return e
|
|
}
|
|
const connect=async():Promise<ProbeStorageConnection>=>{
|
|
leaseCount++;const before=structuredClone({nodes,aliases,events,managedAliases,managedEvents});let committed=false
|
|
const restore=()=>{for(const [target,old]of[[nodes,before.nodes],[aliases,before.aliases],[events,before.events],[managedAliases,before.managedAliases],[managedEvents,before.managedEvents]])target.splice(0,target.length,...old)}
|
|
return{release(){if(!committed)restore()},async query(sql,values=[]){
|
|
queries.push(sql);const rows=(r:Row[]=[],command?:string)=>({rows:structuredClone(r),command})
|
|
if(sql==="BEGIN")return rows([],"BEGIN")
|
|
if(sql==="ROLLBACK"){restore();return rows([],"ROLLBACK")}
|
|
if(sql==="COMMIT"){committed=true;if(commitMode==="lost")throw Error("lost physical ACK");return rows([],commitMode==="rows"?undefined:"COMMIT")}
|
|
if(sql.includes("set_config")||sql.includes("pg_advisory_xact_lock"))return rows()
|
|
if(sql.includes("FROM mmapp_control.bandwidth_node_authority")){if(afterEvent)finalSelect=true;return rows([{installation_id:installationId,issuer_key_sha256:issuerKeySha256,quiescence_proof:quiescenceProof,status:"active"}])}
|
|
const isExternal=sql.includes("bandwidth_external_node_"),a=isExternal?aliases:managedAliases,e=isExternal?events:managedEvents,id=isExternal?"enrollment_id":"server_id"
|
|
if(sql.startsWith("WITH aliases AS MATERIALIZED")){
|
|
const selected=a.filter(row=>row[id]===values[0])
|
|
return rows([{aliases:selected.map(row=>({subject:String(row[id]),incarnation:row.incarnation,node_id:row.node_id,status:row.status,record_mac:row.record_mac})),nodes:nodes.filter(row=>selected.some(alias=>alias.node_id===row.node_id)),events:e.filter(row=>row[id]===values[0]).map(row=>({event_id:row.event_id,incarnation:row.incarnation,node_id:row.node_id,kind:row.kind,old_status:row.old_status,new_status:row.new_status,authority_proof:row.authority_proof,event_mac:row.event_mac})),claim_nodes:values[1]===null?[]:nodes.filter(row=>row.claim_proof===values[1])}],"SELECT")
|
|
}
|
|
if(sql.startsWith("DO $mmapp_bandwidth_register$")){
|
|
// Inert adapter parses only the candidate's validated literal VALUES;
|
|
// this model does not certify PostgreSQL sequential SPI semantics.
|
|
const valuesOf=(table:string)=>{const line=sql.split("\n").find(line=>line.trimStart().startsWith("INSERT INTO mmapp_control."+table+"("));assert(line);const match=/ VALUES\((.*)\)$/.exec(line!);assert(match);return match![1].split(",").map(value=>value.replace(/::pg_catalog\.(?:uuid|text|int8)$/,"" ).replace(/^'|'$/g,""))}
|
|
const node=valuesOf("bandwidth_nodes")
|
|
if(sql.includes("IF true THEN")){assert(!nodes.some(row=>row.claim_proof===node[1]));nodes.push({node_id:node[0],claim_proof:node[1],enrollment_mac:node[2]})}
|
|
else assert(nodes.some(row=>row.node_id===node[0]&&row.claim_proof===node[1]&&row.enrollment_mac===node[2]))
|
|
const alias=valuesOf(isExternal?"bandwidth_external_node_aliases":"bandwidth_node_aliases"),event=valuesOf(isExternal?"bandwidth_external_node_events":"bandwidth_node_events"),subject=isExternal?alias[0]:Number(alias[0])
|
|
assert(!a.some(row=>row[id]===subject));a.push({[id]:subject,incarnation:alias[1],node_id:alias[2],status:alias[3],record_mac:alias[4]})
|
|
e.push({event_id:event[0],[id]:isExternal?event[1]:Number(event[1]),incarnation:event[2],node_id:event[3],kind:event[4],old_status:event[5]==="NULL"?null:event[5],new_status:event[6],authority_proof:event[7],event_mac:event[8]});afterEvent=true
|
|
return rows([],"DO")
|
|
}
|
|
if(sql.startsWith("SELECT")&&sql.includes("FROM mmapp_control.bandwidth_nodes"))return rows(nodes.filter(row=>row[sql.includes("WHERE claim_proof")?"claim_proof":"node_id"]===values[0]))
|
|
if(sql.startsWith("INSERT INTO mmapp_control.bandwidth_nodes")){const row={node_id:values[0],claim_proof:values[1],enrollment_mac:values[2]};assert(!nodes.some(n=>n.claim_proof===row.claim_proof));nodes.push(row);return rows([{node_id:row.node_id}])}
|
|
if(sql.startsWith("SELECT")&&sql.includes("_aliases WHERE"))return rows(a.filter(row=>row[id]===values[0]))
|
|
if(sql.startsWith("SELECT")&&sql.includes("_events WHERE"))return rows(e.filter(row=>row[id]===values[0]).sort((a,b)=>String(a.kind).localeCompare(String(b.kind))))
|
|
if(sql.startsWith("INSERT")&&sql.includes("_aliases(")){const row={[id]:values[0],incarnation:values[1],node_id:values[2],status:"active",record_mac:values[3]};assert(!a.some(r=>r[id]===row[id]));a.push(row);return rows([{[id]:row[id]}])}
|
|
if(sql.startsWith("INSERT")&&sql.includes("_events(")){e.push({event_id:values[0],[id]:values[1],incarnation:values[2],node_id:values[3],kind:values[4],old_status:values[5],new_status:values[6],authority_proof:values[7],event_mac:values[8]});afterEvent=true;return rows([{event_id:values[0]}])}
|
|
if(sql.startsWith("UPDATE")&&sql.includes("_aliases SET")){const row=a.find(r=>r[id]===values[0]&&r.status==="active"&&r.record_mac===values[3]);if(!row)return rows();row.status=values[1];row.record_mac=values[2];return rows([{[id]:row[id]}])}
|
|
throw Error("Unexpected SQL: "+sql)
|
|
}}
|
|
}
|
|
const keyedProof=async(purpose:string,value:unknown)=>{purposes.push(purpose);onProof?.(purpose);return mac(purpose,value)}
|
|
const host=createBandwidthExternalNodeRegistry({now:Date.now,connect,inspect,authorize,keyedProof})
|
|
function observation(enrollmentId:string=randomUUID(),claims:BandwidthPeerObservationEvidence["claims"]=[{kind:"system-id",value:"shared-identity"}]){
|
|
const token={};observations.set(token,{version:2,peerRef:{kind:"external",enrollmentId},claims,sourceProof:"d".repeat(64),authorityGeneration:"source-v2",routingEndpointEpoch:randomUUID(),observedAt:Date.now(),expiresAt:Date.now()+5000,physicalUniquenessVerified:false,cloneResistanceVerified:false});return token
|
|
}
|
|
const managed=createBandwidthNodeRegistry({now:Date.now,connect,authorize,keyedProof,inspect:async()=>({version:1,serverId:42,claims:[{kind:"system-id",value:"shared-identity"}],sourceProof:"d".repeat(64),authorityGeneration:"source-v1",routingEndpointEpoch:installationId,observedAt:1,expiresAt,physicalUniquenessVerified:false,cloneResistanceVerified:false})})
|
|
return{host,managed,observation,nodes,aliases,events,queries,purposes,occupancy,setCommit:(mode:typeof commitMode)=>{commitMode=mode},revoke:()=>{revoked=true},changeKey:()=>{keyChanged=true},revokeAtCommit:()=>{revokeAtCommit=true;afterEvent=false;finalSelect=false;inspectionsAfterSelect=0},proofHook:(hook:typeof onProof)=>{onProof=hook},leases:()=>leaseCount}
|
|
}
|
|
|
|
test("managed and external aliases use the identical issuer/typed claim domain and canonical node; unknown occupancy untouched",async()=>{
|
|
const f=fixture(),before=structuredClone(f.occupancy),managed=await f.managed.register({},scope()),token=f.observation(),external=await f.host.register(token,scope())
|
|
assert.equal(external.canonicalNodeId,managed.canonicalNodeId);assert.notEqual(external.incarnation,managed.incarnation);assert.equal(f.nodes.length,1)
|
|
assert.equal((await f.host.resolve(token,scope())).canonicalNodeId,managed.canonicalNodeId)
|
|
assert.equal((await f.host.register(token,scope())).outcome,"existing");assert.equal(f.events.length,1)
|
|
assert(f.purposes.includes("external-alias"));assert(f.purposes.includes("external-event"));assert.deepEqual(f.occupancy,before)
|
|
assert(f.queries.includes("SELECT pg_catalog.pg_advisory_xact_lock(8723116)"));assert(!f.queries.some(q=>/occupancy|bandwidth_attempt/.test(q)))
|
|
})
|
|
test("external terminal alias cannot reactivate/rebind; fresh alias preserves node and unknown",async()=>{
|
|
const f=fixture(),token=f.observation(),first=await f.host.register(token,scope())
|
|
assert.equal((await f.host.retire(first.enrollmentId,"tombstone",scope())).status,"tombstoned")
|
|
assert.equal((await f.host.retire(first.enrollmentId,"tombstone",scope())).outcome,"existing")
|
|
await assert.rejects(f.host.register(token,scope()));await assert.rejects(f.host.resolve(token,scope()));await assert.rejects(f.host.retire(first.enrollmentId,"quarantine",scope()))
|
|
const replacement=await f.host.register(f.observation(),scope());assert.equal(replacement.canonicalNodeId,first.canonicalNodeId);assert.notEqual(replacement.incarnation,first.incarnation);assert.equal(f.events.length,3)
|
|
})
|
|
test("resolve absent, cloned observation, invalid enrollment and mismatched license do not auto-enroll",async()=>{
|
|
const f=fixture(),token=f.observation();await assert.rejects(f.host.resolve(token,scope()));assert.equal(f.nodes.length,0)
|
|
await assert.rejects(f.host.register({...token},scope()));await assert.rejects(f.host.retire("42","tombstone",scope()));assert.equal(f.nodes.length,0)
|
|
const first=await f.host.register(token,scope());await assert.rejects(f.host.register(f.observation(first.enrollmentId,[{kind:"software-id",value:"shared-identity"}]),scope()));assert.equal(f.nodes.length,1)
|
|
})
|
|
test("full typed license vector and claim kind remain distinct",async()=>{
|
|
const f=fixture(),ids=[]
|
|
for(const claims of [[{kind:"system-id",value:"ONE"}],[{kind:"software-id",value:"ONE"}],[{kind:"system-id",value:"ONE"},{kind:"software-id",value:"TWO"}]] as BandwidthPeerObservationEvidence["claims"][])ids.push((await f.host.register(f.observation(undefined,claims),scope())).canonicalNodeId)
|
|
assert.equal(new Set(ids).size,3)
|
|
})
|
|
test("revocation or issuer drift during proof prevents writes, destroys lease and rolls back",async()=>{
|
|
for(const change of ["revoke","changeKey"] as const){const f=fixture();f.proofHook(purpose=>{if(purpose==="external-event")f[change]()});await assert.rejects(f.host.register(f.observation(),scope()),BandwidthExternalNodeRegistryError);assert.equal(f.nodes.length,0);assert.equal(f.aliases.length,0);assert(!f.queries.includes("COMMIT"));assert(f.queries.includes("ROLLBACK"))}
|
|
})
|
|
test("original grant is checked after final asynchronous inspection before COMMIT",async()=>{
|
|
const f=fixture();f.revokeAtCommit();await assert.rejects(f.host.register(f.observation(),scope()),BandwidthExternalNodeRegistryError);assert(!f.queries.includes("COMMIT"));assert.equal(f.aliases.length,0)
|
|
})
|
|
test("lost or rows-only physical COMMIT ACK is unknown, no replay or post-COMMIT rollback; fresh resolve reconciles",async()=>{
|
|
for(const mode of ["lost","rows"] as const){const f=fixture(),token=f.observation();f.setCommit(mode);await assert.rejects(f.host.register(token,scope()),error=>error instanceof BandwidthExternalNodeRegistryUnknown&&error.automaticReplay===false);assert.equal(f.aliases.length,1);assert.equal(f.events.length,1);assert.equal(f.queries.filter(q=>q==="COMMIT").length,1);assert(!f.queries.includes("ROLLBACK"));f.setCommit("ok");assert.equal((await f.host.resolve(token,scope())).canonicalNodeId,f.nodes[0].node_id);assert.equal(f.events.length,1)}
|
|
})
|
|
test("prior alias/node/event MAC tampering refuses without replacement identity",async()=>{
|
|
for(const target of ["aliases","nodes","events"] as const){const f=fixture(),token=f.observation();await f.host.register(token,scope());const rows=f[target];rows[0][target==="aliases"?"record_mac":target==="nodes"?"enrollment_mac":"event_mac"]="f".repeat(64);await assert.rejects(f.host.resolve(token,scope()));assert.equal(f.nodes.length,1);assert.equal(f.events.length,1)}
|
|
})
|