@uuaid/agent-commons 0.0.0-stage → 0.2.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CONFORMANCE.md +26 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +25 -0
  4. package/PROVENANCE.json +29 -0
  5. package/README.md +316 -2
  6. package/bin/agent-commons.mjs +71 -0
  7. package/examples/Dockerfile +12 -0
  8. package/examples/agent.mjs +17 -0
  9. package/examples/global-policy.json +9 -0
  10. package/examples/run-cohort.mjs +68 -0
  11. package/package.json +31 -4
  12. package/profiles/agentnet.chat.json +11 -0
  13. package/profiles/local.json +11 -0
  14. package/profiles/zilligon.com.json +11 -0
  15. package/profiles/zilligons.com.json +11 -0
  16. package/src/carrier.mjs +79 -0
  17. package/src/channels.d.mts +75 -0
  18. package/src/channels.mjs +158 -0
  19. package/src/cohort.mjs +61 -0
  20. package/src/collaboration.mjs +875 -0
  21. package/src/config.mjs +39 -0
  22. package/src/continuity.d.mts +24 -0
  23. package/src/continuity.mjs +594 -0
  24. package/src/governance-scope.d.mts +46 -0
  25. package/src/governance-scope.mjs +139 -0
  26. package/src/governance.mjs +353 -0
  27. package/src/index.d.ts +109 -0
  28. package/src/index.mjs +15 -0
  29. package/src/loop.mjs +71 -0
  30. package/src/offline.d.mts +7 -0
  31. package/src/offline.mjs +29 -0
  32. package/src/pillar.mjs +59 -0
  33. package/src/profiles.d.mts +12 -0
  34. package/src/profiles.mjs +91 -0
  35. package/src/runtime.mjs +346 -0
  36. package/src/store.mjs +73 -0
  37. package/src/transport.d.mts +76 -0
  38. package/src/transport.mjs +267 -0
  39. package/src/trust.mjs +65 -0
  40. package/src/vendor/pillar/blob/blob.mjs +510 -0
  41. package/src/vendor/pillar/crypto/e2e.mjs +97 -0
  42. package/src/vendor/pillar/identity/jcs.mjs +35 -0
  43. package/src/vendor/pillar/identity/keychain.mjs +192 -0
  44. package/src/vendor/pillar/identity/tier.mjs +130 -0
  45. package/src/vendor/pillar/net/carrier-client.mjs +197 -0
  46. package/src/vendor/pillar/net/delegation.mjs +209 -0
  47. package/src/vendor/pillar/net/envelope.mjs +258 -0
  48. package/src/vendor/pillar/net/refusals.mjs +127 -0
  49. package/src/vendor/pillar/net/seed-tier.mjs +185 -0
  50. package/test/channels.test.mjs +268 -0
  51. package/test/cohort.test.mjs +36 -0
  52. package/test/collaboration.test.mjs +459 -0
  53. package/test/continuity.test.mjs +229 -0
  54. package/test/custody.negative.test.mjs +165 -0
  55. package/test/derivation-parity.test.mjs +19 -0
  56. package/test/fixtures/derivation-vectors.json +26 -0
  57. package/test/fixtures/ed25519-small-order.vectors.json +15 -0
  58. package/test/governance-expected-red.expected-red.mjs +241 -0
  59. package/test/governance-scope.test.mjs +142 -0
  60. package/test/governance-t1-t10.test.mjs +477 -0
  61. package/test/governance.test.mjs +514 -0
  62. package/test/hold-admission.test.mjs +1185 -0
  63. package/test/keychain-strict-ed25519.test.mjs +240 -0
  64. package/test/offline.test.mjs +152 -0
  65. package/test/runtime-channels.test.mjs +1140 -0
  66. package/test/runtime.test.mjs +201 -0
  67. package/test/security-runtime.test.mjs +104 -0
  68. package/test/strict-ed25519-consumers.test.mjs +234 -0
  69. package/test/transport.test.mjs +353 -0
@@ -0,0 +1,201 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtempSync, readFileSync, rmSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { createHash } from "node:crypto";
7
+ import { AgentCommons,CommonsStore,CommonsCarrier,RegistryTrust,Keychain,CarrierClient,createProfile,encode,decode,seal,open,signDocument,verifyDocument,contribution,REQUIRED_STANDARDS,runAgentLoop } from "../src/index.mjs";
8
+ import { initialize,loadRuntime } from "../src/config.mjs";
9
+ function key(){const k=new Keychain("unused");k._identity=Keychain.generate();return k}
10
+ function setup(scope="local"){
11
+ const keys=[key(),key(),key(),key()];
12
+ const policy={mode:"local",agents:Object.fromEntries(keys.map(k=>[k._identity.uuaid,{kind:"agent",publicKey:k._identity.publicKeyHex,capabilities:["commons:message","commons:relay","commons:evolve","commons:contribute","commons:recover"]}]))};
13
+ const runtimes=keys.map(k=>new AgentCommons({keychain:k,policy}));
14
+ const profile=createProfile({namespace:"test/fleet",name:"Fixture profile",scope,fixtures:["Require semantic equivalence and semantic equivalence.","Preserve semantic equivalence before accepting a profile."]});
15
+ runtimes.forEach(r=>{if(scope!=="global")r.addProfile(profile);else r.store.set("profiles",[profile])});
16
+ return {keys,policy,runtimes,profile};
17
+ }
18
+ test("published Pillar source subset matches provenance byte for byte",()=>{
19
+ const manifest=JSON.parse(readFileSync(new URL("../PROVENANCE.json",import.meta.url)));
20
+ let tarballCount=0,localCount=0;
21
+ for(const [file,entry] of Object.entries(manifest.files)){
22
+ const expectedHash=typeof entry==="string"?entry:entry.sha256;
23
+ const actualHash=createHash("sha256").update(readFileSync(new URL(`../src/vendor/pillar/${file}`,import.meta.url))).digest("hex");
24
+ assert.equal(actualHash,expectedHash,`hash mismatch for ${file}`);
25
+ if(typeof entry==="string"){
26
+ tarballCount++;
27
+ } else {
28
+ assert.equal(entry.source,"pillar commit 2ef548d (local, no remote - not published)");
29
+ localCount++;
30
+ }
31
+ }
32
+ assert.equal(tarballCount,7,"7 files from 2.0.2 tarball");
33
+ assert.equal(localCount,3,"3 files from 2ef548d local");
34
+ assert.equal(manifest.upstreamVersion,"2.0.2");
35
+ });
36
+ test("500 lossless alias/Unicode/control-token combinations",()=>{
37
+ const lexicon={"semantic equivalence":"~0~","Require semantic equivalence":"~1~"};
38
+ const samples=["semantic equivalence","~0~","~~","தமிழ்","\n","Require semantic equivalence","🧬"];
39
+ for(let i=0;i<500;i++){const text=[samples[i%7],samples[(i*3)%7],String.fromCodePoint(0x1f600+i%80)].join(" ");assert.equal(decode(encode(text,lexicon),lexicon),text)}
40
+ });
41
+ test("bad aliases and bounded-fixture violations fail closed",()=>{
42
+ const options={namespace:"test/a",name:"A profile",fixtures:["semantic equivalence","semantic equivalence"]};
43
+ assert.throws(()=>createProfile({...options,lexicon:{"semantic equivalence":"~0~","communication profile":"~0~"}}),/colliding/);
44
+ assert.throws(()=>createProfile({...options,fixtures:["only one"]}),/2–100/);
45
+ });
46
+ test("one deployable home initializes without registry writes and never overwrites",()=>{
47
+ const home=mkdtempSync(join(tmpdir(),"ac-init-"));
48
+ try{const first=initialize({home,target:"zilligons.com"});assert.match(first.identity.uuaid,/^uuaid:foundation:agent:/);const loaded=loadRuntime(home);assert.equal(loaded.runtime.profiles().length,1);assert.equal(loaded.runtime.status().auditVerified,true);loaded.store.close();assert.throws(()=>initialize({home}),/not overwritten/);assert.equal(first.certified,false)}finally{rmSync(home,{recursive:true,force:true})}
49
+ });
50
+ test("two genuinely independent signed votes adopt a local profile",async()=>{
51
+ const {runtimes:[a,b,c],profile}=setup();
52
+ const proposal=await a.propose(profile.id,"semantic equivalence");
53
+ assert.equal((await b.apply(proposal)).status,"pending");
54
+ const voteB=await b.vote(proposal.payload.proposal.id,true,"Measured and reversible");
55
+ assert.equal((await a.apply(voteB)).status,"pending");
56
+ const voteC=await c.vote(proposal.payload.proposal.id,true,"Independent lossless check");
57
+ assert.equal((await a.apply(voteC)).status,"adopted");
58
+ assert.equal(a.profiles().length,2);assert.equal(a.store.verify(),true);
59
+ });
60
+ test("parallel independent votes are serialized without losing a ballot",async()=>{
61
+ const {runtimes:[a,b,c],profile}=setup();
62
+ const p=await a.propose(profile.id,"semantic equivalence");
63
+ const [vb,vc]=await Promise.all([b.vote(p.payload.proposal.id,true),c.vote(p.payload.proposal.id,true)]);
64
+ const outcomes=await Promise.all([a.apply(vb),a.apply(vc)]);assert.equal(outcomes.at(-1).status,"adopted");
65
+ });
66
+ test("self vote, second vote under a new ID, and tampering are rejected",async()=>{
67
+ const {runtimes:[a,b],keys,profile}=setup();const p=await a.propose(profile.id,"semantic equivalence");
68
+ await assert.rejects(a.apply(await a.vote(p.payload.proposal.id,true)),/Ineligible/);
69
+ await a.apply(await b.vote(p.payload.proposal.id,true));
70
+ await assert.rejects(a.apply(await b.vote(p.payload.proposal.id,true)),/duplicate/);
71
+ const modified=structuredClone(p);modified.payload.proposal.phrase="different phrase";assert.throws(()=>verifyDocument(modified),/signature/);
72
+ });
73
+ test("positive ballots are revalidated after a voter is blocked",async()=>{
74
+ const {runtimes:[a,b,c],policy,profile}=setup();const p=await a.propose(profile.id,"semantic equivalence");
75
+ await a.apply(await b.vote(p.payload.proposal.id,true));policy.blocked=[b.uuaid];
76
+ await assert.rejects(a.apply(await c.vote(p.payload.proposal.id,true)),/blocked/);assert.equal(a.profiles().length,1);
77
+ });
78
+ test("local ballots cannot mutate a global profile",async()=>{
79
+ const {runtimes:[a,b,c],profile}=setup("global");const p=await a.propose(profile.id,"semantic equivalence");await a.apply(await b.vote(p.payload.proposal.id,true));
80
+ await assert.rejects(a.apply(await c.vote(p.payload.proposal.id,true)),/cannot ratify global/);
81
+ });
82
+ test("metadata-only contributions do not leak fixtures or claim ratification",async()=>{
83
+ const {runtimes:[a,b],profile}=setup();const document=await a.prepareContribution(profile.id);
84
+ assert.equal(document.payload.contribution.profile,undefined);assert.equal(contribution(profile).stage,"candidate");
85
+ const result=await b.apply(document);assert.equal(result.ratified,false);assert.equal(result.stage,"awaiting-independent-review");
86
+ });
87
+ test("unadmitted and human-type identities are denied",async()=>{
88
+ const {runtimes:[a],keys}=setup();const unknown=key();
89
+ await assert.rejects(a.trust.authorize(unknown._identity.uuaid,unknown._identity.publicKeyHex),/not been admitted/);
90
+ await assert.rejects(a.trust.authorize(keys[0]._identity.uuaid.replace(":agent:",":human:"),keys[0]._identity.publicKeyHex),/agent UUAID/);
91
+ });
92
+ test("Pillar sealed payloads are actually private and tamper evident",async()=>{
93
+ const {runtimes:[a,b],profile}=setup();const sent=await a.send({recipient:b.uuaid,profileId:profile.id,body:"semantic equivalence"});
94
+ assert.equal(JSON.stringify(sent.envelope).includes("semantic equivalence"),false);assert.equal(open(sent.envelope).ok,true);
95
+ assert.equal((await b.receive(sent.envelope)).body,"semantic equivalence");assert.equal((await b.receive(sent.envelope)).duplicate,true);
96
+ const changed=structuredClone(sent.envelope);changed.enc.ct="00"+changed.enc.ct.slice(2);await assert.rejects(b.receive(changed),/Invalid Pillar envelope/);
97
+ });
98
+ test("unknown profile digests never silently downgrade to another decoder",async()=>{
99
+ const {runtimes:[a,b],profile}=setup();const sent=await a.send({recipient:b.uuaid,profileId:profile.id,body:"semantic equivalence"});b.store.set("profiles",[]);
100
+ await assert.rejects(b.receive(sent.envelope),/Unknown local profile/);
101
+ });
102
+ test("official published CarrierClient delivers, authenticates inbox, and deduplicates",async()=>{
103
+ const {keys,policy,runtimes:[a,b],profile}=setup();const store=new CommonsStore();const carrier=new CommonsCarrier({store,trust:new RegistryTrust({policy})});const address=await carrier.listen();
104
+ try{
105
+ const url=`http://127.0.0.1:${address.port}`,client=new CarrierClient({keychain:keys[0],carriers:[url]});
106
+ const sent=await a.send({recipient:b.uuaid,profileId:profile.id,body:"Preserve semantic equivalence."});
107
+ const first=await client.deliver(sent.envelope),second=await client.deliver(sent.envelope);assert.equal(first.duplicate,false);assert.equal(second.duplicate,true);
108
+ const recipientClient=new CarrierClient({keychain:keys[1],carriers:[url]});
109
+ const fetched=await recipientClient.fetchInbox(url,{waitS:0});assert.equal(fetched.envelopes.length,1);assert.equal((await b.receive(fetched.envelopes[0].envelope)).body,"Preserve semantic equivalence.");
110
+ assert.equal(store.verify(),true);
111
+ const unauthorized=await fetch(`${url}/v1/inbox/${b.uuaid}`);assert.equal(unauthorized.status,401);
112
+ const human=await fetch(`${url}/v1/envelopes`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({body:"human post"})});assert.equal(human.status,400);
113
+ assert.equal((await (await fetch(`${url}/.well-known/agent-commons`)).json()).role,"carrier");
114
+ }finally{await carrier.close();store.close()}
115
+ });
116
+ test("long polling wakes on delivery instead of spinning or waiting the full timer",async()=>{
117
+ const {keys,policy,runtimes:[a,b],profile}=setup();const carrier=new CommonsCarrier({trust:new RegistryTrust({policy})});const address=await carrier.listen();
118
+ try{
119
+ const url=`http://127.0.0.1:${address.port}`,receiver=new CarrierClient({keychain:keys[1],carriers:[url]});
120
+ const pending=receiver.fetchInbox(url,{waitS:5,timeoutMs:8000});
121
+ const sent=await a.send({recipient:b.uuaid,profileId:profile.id,body:"wake peer"});
122
+ await new CarrierClient({keychain:keys[0],carriers:[url]}).deliver(sent.envelope);
123
+ assert.equal((await pending).envelopes.length,1);
124
+ }finally{await carrier.close();carrier.store.close()}
125
+ });
126
+ test("persistent outbox quarantine, recovery pin, and audit tampering",async()=>{
127
+ const {runtimes:[a,b],keys,profile}=setup();await a.send({recipient:b.uuaid,profileId:profile.id,body:"queued"});
128
+ const row=a.store.pending()[0];for(let i=0;i<5;i++)a.store.failure(row.id,"unreachable");assert.equal(a.store.db.prepare("SELECT state FROM outbox WHERE id=?").get(row.id).state,"quarantined");
129
+ const recovery=signDocument(keys[0],"profile-recovery",{profileId:profile.id,reason:"Restore known local decoder"});assert.equal((await a.apply(recovery)).status,"local-profile-pinned");
130
+ a.store.db.prepare("UPDATE events SET body=? WHERE seq=1").run('{"bad":true}');assert.equal(a.store.verify(),false);
131
+ });
132
+ test("global admission uses official SDK verification, subject binding, and IAASO pins",async()=>{
133
+ const {keys,policy}=setup();const id=keys[0]._identity.uuaid,publicKey=keys[0]._identity.publicKeyHex;
134
+ const globalPolicy={...policy,mode:"global",standardPins:Object.fromEntries(REQUIRED_STANDARDS.map(code=>[code,"a".repeat(64)]))};
135
+ globalPolicy.agents[id]={...globalPolicy.agents[id],credentialId:"credential-test"};
136
+ const fetchImpl=async url=>{
137
+ if(url.includes("/v1/standards"))return new Response(JSON.stringify({standards:REQUIRED_STANDARDS.map(code=>({code,stage:"published",content_hash:"a".repeat(64)}))}));
138
+ if(url.includes("/resolve/"))return new Response(JSON.stringify({agent:{uuaid:id,status:"active"}}));
139
+ return new Response(JSON.stringify({credential_id:"credential-test",agent_uuaid:id,valid:true,signatureValid:true,active:true,notExpired:true}));
140
+ };
141
+ const trust=new RegistryTrust({policy:globalPolicy,fetchImpl});assert.equal((await trust.authorize(id,publicKey)).tier,"registry-credential-and-policy");
142
+ const broken=new RegistryTrust({policy:{...globalPolicy,standardPins:{}},fetchImpl});await assert.rejects(broken.authorize(id,publicKey),/pinned/);
143
+ const revoked=new RegistryTrust({policy:globalPolicy,fetchImpl:async url=>url.includes("/verify/")?new Response(JSON.stringify({credential_id:"credential-test",agent_uuaid:id,valid:true,signatureValid:true,active:false,notExpired:true})):fetchImpl(url)});await assert.rejects(revoked.authorize(id,publicKey),/expiry failed/);
144
+ });
145
+ test("global profiles require an exact published content hash and no fail-open fallback",async()=>{
146
+ const {runtimes:[a]}=setup();const p=createProfile({namespace:"global/test",name:"Global draft",scope:"global",fixtures:["first test fixture","second test fixture"]});
147
+ a.trust.publishedProfilePin=async()=>{throw new Error("No IAASO publication")};await assert.rejects(a.importGlobal(p,"UNASSIGNED-DRAFT"),/No IAASO/);
148
+ });
149
+ test("public carrier binding without global policy and HTTPS fails",async()=>{
150
+ const carrier=new CommonsCarrier();await assert.rejects(carrier.listen(0,"0.0.0.0"),/Public bind requires/);carrier.store.close();
151
+ });
152
+ test("provider-neutral bounded agent loop supports spontaneous engagement",async()=>{
153
+ let calls=0;const runtime={poll:async()=>[],flush:async()=>[],status:()=>({}),send:async action=>{calls++;return action}};
154
+ const result=await runAgentLoop({runtime,respond:async()=>null,spontaneous:async()=>({recipient:"test",profileId:"fixture",body:"autonomous turn"}),maxTurns:1,intervalMs:500});
155
+ assert.equal(calls,1);assert.equal(result.stopped,"turn-limit");
156
+ });
157
+ test("unknown policy mode never degrades to permissive local operation",()=>{
158
+ assert.throws(()=>new RegistryTrust({policy:{mode:"globla"}}),/explicitly local or global/);
159
+ });
160
+ test("bounded multi-agent broadcasts seal separately to every recipient",async()=>{
161
+ const {runtimes:[a,b,c],profile}=setup();
162
+ const batch=await a.broadcast({recipients:[b.uuaid,c.uuaid],profileId:profile.id,body:"semantic equivalence"});
163
+ assert.equal(batch.queued.length,2);
164
+ const envelopes=a.store.pending().map(r=>JSON.parse(r.body));
165
+ assert.notEqual(envelopes[0].enc.ct,envelopes[1].enc.ct);
166
+ assert.equal((await b.receive(envelopes[0])).body,"semantic equivalence");
167
+ assert.equal((await c.receive(envelopes[1])).body,"semantic equivalence");
168
+ await assert.rejects(a.broadcast({recipients:[b.uuaid,b.uuaid],profileId:profile.id,body:"duplicate"}),/distinct/);
169
+ });
170
+ test("polling fails over to healthy carriers with persistent bounded backoff",async()=>{
171
+ const {runtimes:[a,b],keys,policy,profile}=setup();const sent=await a.send({recipient:b.uuaid,profileId:profile.id,body:"semantic equivalence"});
172
+ const runtime=new AgentCommons({keychain:keys[1],policy,carriers:["http://bad.invalid","http://healthy.invalid"]});runtime.addProfile(profile);
173
+ runtime.transport.fetchInbox=async carrier=>{if(carrier.includes("bad"))throw new Error("offline");return {envelopes:[{seq:1,envelope:sent.envelope}]}};
174
+ const results=await runtime.poll();assert.equal(results[0].state,"retry-backoff");assert.equal(results[1].body,"semantic equivalence");
175
+ assert.ok(runtime.store.get("carrierHealth")["http://bad.invalid"].nextProbeAt>Date.now());
176
+ });
177
+ test("quarantined outbox recovery revalidates signatures and does not send",async()=>{
178
+ const {runtimes:[a,b],profile}=setup();const sent=await a.send({recipient:b.uuaid,profileId:profile.id,body:"recover"});
179
+ for(let i=0;i<5;i++)a.store.failure(sent.envelope.id,"offline");
180
+ const result=await a.retryOutbox(sent.envelope.id);assert.equal(result.networkCallMade,false);assert.equal(a.store.pending().length,1);
181
+ assert.equal(a.store.verify(),true);
182
+ });
183
+ test("local recovery changes the decoder used for namespace-selected sends",async()=>{
184
+ const {runtimes:[a,b,c],keys,profile}=setup();const proposal=await a.propose(profile.id,"semantic equivalence");
185
+ await a.apply(await b.vote(proposal.payload.proposal.id,true));await a.apply(await c.vote(proposal.payload.proposal.id,true));
186
+ assert.notEqual(a.activeProfile(profile.namespace).id,profile.id);
187
+ await a.apply(signDocument(keys[0],"profile-recovery",{profileId:profile.id,reason:"Pin the known baseline"}));
188
+ const queued=await a.send({recipient:b.uuaid,namespace:profile.namespace,body:"semantic equivalence"});
189
+ assert.equal(a.activeProfile(profile.namespace).id,profile.id);
190
+ assert.equal((await b.receive(queued.envelope)).body,"semantic equivalence");
191
+ const next=await a.propose(profile.id,"Preserve semantic equivalence");
192
+ await a.apply(await b.vote(next.payload.proposal.id,true));await a.apply(await c.vote(next.payload.proposal.id,true));
193
+ assert.equal(a.activeProfile(profile.namespace).id,next.payload.proposal.candidate.id);
194
+ });
195
+ test("confirmed singular deployment target and old spelling normalize consistently",()=>{
196
+ const singular=mkdtempSync(join(tmpdir(),"ac-singular-")),alias=mkdtempSync(join(tmpdir(),"ac-alias-"));
197
+ try{
198
+ const a=initialize({home:singular,target:"zilligon.com"}),b=initialize({home:alias,target:"zilligons.com"});
199
+ assert.equal(a.target,"zilligon.com");assert.equal(b.target,"zilligon.com");assert.equal(a.profileId,b.profileId);
200
+ }finally{rmSync(singular,{recursive:true,force:true});rmSync(alias,{recursive:true,force:true})}
201
+ });
@@ -0,0 +1,104 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { AgentCommons,CommonsStore,RegistryTrust,Keychain,createProfile,signDocument,runAgentLoop,seal } from "../src/index.mjs";
4
+ import { isTransientTrustFailure } from "../src/trust.mjs";
5
+ const CAPS=["commons:message","commons:relay","commons:evolve","commons:contribute","commons:recover"];
6
+ function key(){const k=new Keychain("unused");k._identity=Keychain.generate();return k}
7
+ function setup(n=3){
8
+ const keys=Array.from({length:n},key);
9
+ const policy={mode:"local",agents:Object.fromEntries(keys.map(k=>[k._identity.uuaid,{kind:"agent",publicKey:k._identity.publicKeyHex,capabilities:CAPS}]))};
10
+ const runtimes=keys.map(k=>new AgentCommons({keychain:k,policy}));
11
+ const profile=createProfile({namespace:"test/sec",name:"Security fixture",fixtures:["Require semantic equivalence and semantic equivalence.","Preserve semantic equivalence before accepting a profile."]});
12
+ runtimes.forEach(r=>r.addProfile(profile));
13
+ return {keys,policy,runtimes,profile};
14
+ }
15
+ // --- Duplicate-key quorum (B3) ---
16
+ test("one key admitted under two UUAID spellings is denied (policy-level Sybil)",async()=>{
17
+ const {keys,policy}=setup(2);const k=keys[0]._identity;
18
+ const alias=k.uuaid.replace(":foundation:",":spoof:");
19
+ policy.agents[alias]={...policy.agents[k.uuaid]};
20
+ const trust=new RegistryTrust({policy});
21
+ await assert.rejects(trust.authorize(k.uuaid,k.publicKeyHex,"commons:evolve"),/more than one UUAID/);
22
+ await assert.rejects(trust.authorize(alias,k.publicKeyHex,"commons:evolve"),/more than one UUAID/);
23
+ });
24
+ test("proposer's key cannot approve its own proposal through a second spelling, and one key cannot double-vote",async()=>{
25
+ const {keys,policy,runtimes:[a,b,c],profile}=setup(3);
26
+ const p=await a.propose(profile.id,"semantic equivalence");
27
+ await a.apply(await b.vote(p.payload.proposal.id,true));
28
+ // Forge-free scenario: same key, different issuer string, signed with the real key. Admission is denied at policy level.
29
+ const alias=keys[1]._identity.uuaid.replace(":foundation:",":spoof:");
30
+ policy.agents[alias]={...policy.agents[keys[1]._identity.uuaid]};
31
+ const spoof={...keys[1],_identity:{...keys[1]._identity,uuaid:alias},sign:data=>keys[1].sign(data)};
32
+ const doc=signDocument(spoof,"profile-vote",{proposalId:p.payload.proposal.id,approve:true,rationale:"dup"});
33
+ await assert.rejects(a.apply(doc),/more than one UUAID|Ineligible/);
34
+ assert.equal(a.profiles().length,1);
35
+ });
36
+ // --- Reliable cursors / trust outage (H1-H3) ---
37
+ test("transient trust failure does not advance the cursor or drop the message; it is delivered after recovery",async()=>{
38
+ const {keys,policy,runtimes:[a,b],profile}=setup(2);
39
+ const sent=await a.send({recipient:b.uuaid,profileId:profile.id,body:"semantic equivalence"});
40
+ const rt=new AgentCommons({keychain:keys[1],policy,carriers:["http://c.invalid"]});rt.addProfile(profile);
41
+ rt.transport.fetchInbox=async(_c,{since})=>({envelopes:[{seq:7,envelope:sent.envelope}].filter(x=>x.seq>since)});
42
+ let down=true;const real=rt.trust.authorize.bind(rt.trust);
43
+ rt.trust.authorize=async(...args)=>{if(down){const {TrustError}=await import("../src/trust.mjs");throw new TrustError("AUTHORITY_UNAVAILABLE","down",{transient:true})}return real(...args)};
44
+ const first=await rt.poll();
45
+ assert.equal(first[0].deferred,true);assert.equal(rt.store.get("cursors",{})["http://c.invalid"]??0,0);
46
+ down=false;rt.store.set("carrierHealth",{});
47
+ const second=await rt.poll();
48
+ assert.equal(second[0].body,"semantic equivalence");assert.equal(rt.store.get("cursors")["http://c.invalid"],7);
49
+ });
50
+ test("permanent rejection still advances the cursor; carrier cannot rewind sequence numbers",async()=>{
51
+ const {keys,policy,runtimes:[a,b],profile}=setup(2);
52
+ const m1=await a.send({recipient:b.uuaid,profileId:profile.id,body:"semantic equivalence"});
53
+ const rt=new AgentCommons({keychain:keys[1],policy,carriers:["http://c.invalid"]});rt.addProfile(profile);
54
+ const bad={id:"garbage"};
55
+ rt.transport.fetchInbox=async()=>({envelopes:[{seq:5,envelope:bad},{seq:3,envelope:m1.envelope}]});
56
+ const r=await rt.poll();
57
+ assert.equal(r[0].rejected,true);assert.equal(r[1].reason,"non-monotonic-carrier-sequence");
58
+ assert.equal(rt.store.get("cursors")["http://c.invalid"],5);
59
+ });
60
+ test("transient classification: network errors transient, registry 4xx permanent",()=>{
61
+ assert.equal(isTransientTrustFailure(new Error("ECONNRESET")),true);
62
+ assert.equal(isTransientTrustFailure(Object.assign(new Error("x"),{status:503})),true);
63
+ assert.equal(isTransientTrustFailure(Object.assign(new Error("x"),{status:404})),false);
64
+ });
65
+ test("a peer-chosen message ID cannot censor a signed control document with the same ID",async()=>{
66
+ const {keys,runtimes:[a,b,c],profile}=setup(3);
67
+ const p=await a.propose(profile.id,"semantic equivalence");
68
+ const vote=await b.vote(p.payload.proposal.id,true);
69
+ // Attacker c delivers a plain message whose payload.id equals the vote document ID, using a's real receive path.
70
+ const payload={v:"agent-commons/1",id:vote.id,kind:"message",thread:"t",profileId:profile.id,wire:"hello",bodyHash:(await import("../src/profiles.mjs")).digest("hello"),expiresAt:new Date(Date.now()+60000).toISOString()};
71
+ const env=seal(keys[2],{recipient:a.uuaid,recipientPublicKey:a.publicKey,kind:"agent-commons/1",payload});
72
+ const got=await a.receive(env);assert.equal(got.body,"hello");
73
+ assert.equal((await a.apply(vote)).status,"pending");
74
+ });
75
+ // --- Budget loop (B4) ---
76
+ function fakeRuntime(){
77
+ const store=new CommonsStore();let inbound=0;const sent=[];
78
+ return {store,sent,policy:{agents:{peer:{}}},status:()=>({}),flush:async()=>[],
79
+ poll:async()=>[{id:`m${inbound++}`,sender:"peer",profileId:"p",thread:"t",body:"ping"}],
80
+ send:async a=>{sent.push(a);return {id:"x"}}};
81
+ }
82
+ test("reply ping-pong stops at the per-peer run budget and records a refusal",async()=>{
83
+ const rt=fakeRuntime();
84
+ const r=await runAgentLoop({runtime:rt,respond:async()=>"pong",maxTurns:100,intervalMs:500,budget:{maxRepliesPerPeer:3}});
85
+ assert.equal(rt.sent.length,3);assert.equal(r.stopped,"budget:run-peer-replies");
86
+ assert.ok(rt.store.audit().some(e=>e.body.includes("loop-budget-stop")));
87
+ });
88
+ test("persisted window budget survives loop restarts",async()=>{
89
+ const rt=fakeRuntime();
90
+ for(let i=0;i<3;i++)await runAgentLoop({runtime:rt,respond:async()=>"pong",maxTurns:2,intervalMs:500,budget:{windowMaxSends:3}});
91
+ assert.equal(rt.sent.length,3);
92
+ });
93
+ test("spontaneous action cannot be a control message or target an unadmitted peer",async()=>{
94
+ const rt=fakeRuntime();rt.poll=async()=>[];const events=[];
95
+ await runAgentLoop({runtime:rt,respond:async()=>null,spontaneous:async()=>({recipient:"peer",kind:"profile-control",body:"{}"}),maxTurns:1,intervalMs:500,onEvent:e=>events.push(e)});
96
+ await runAgentLoop({runtime:rt,respond:async()=>null,spontaneous:async()=>({recipient:"stranger",body:"hi"}),maxTurns:1,intervalMs:500,onEvent:e=>events.push(e)});
97
+ assert.equal(rt.sent.length,0);assert.equal(events.filter(e=>e.state==="spontaneous-action-refused").length,2);
98
+ });
99
+ test("budget values above hard ceilings are rejected; responder failure does not kill the loop",async()=>{
100
+ const rt=fakeRuntime();
101
+ await assert.rejects(runAgentLoop({runtime:rt,respond:async()=>null,budget:{maxSends:100000}}),/Invalid loop budget/);
102
+ const r=await runAgentLoop({runtime:rt,respond:async()=>{throw new Error("model down")},maxTurns:2,intervalMs:500});
103
+ assert.equal(r.turns,2);
104
+ });
@@ -0,0 +1,234 @@
1
+ // L12: Consumer Poles and C6 Verification for Strict Ed25519 Keys
2
+ import test from "node:test";
3
+ import assert from "node:assert/strict";
4
+ import { randomUUID } from "node:crypto";
5
+ import {
6
+ AgentCommons,
7
+ CommonsStore,
8
+ CommonsCarrier,
9
+ RegistryTrust,
10
+ Keychain,
11
+ seal,
12
+ open,
13
+ MemoryLoopbackTransport,
14
+ } from "../src/index.mjs";
15
+ import { ContinuityMemory, MemoryContinuityStore, ContinuityError } from "../src/continuity.mjs";
16
+ import { verifyGovernanceDocument, GovernanceError } from "../src/governance.mjs";
17
+ import { verifyDocument, digest } from "../src/profiles.mjs";
18
+
19
+ const IDENTITY = "01" + "00".repeat(31);
20
+ const FORGED_SIG = "01" + "00".repeat(31) + "00".repeat(32);
21
+
22
+ function makeKey() {
23
+ const k = new Keychain("test-key");
24
+ k._identity = Keychain.generate();
25
+ return k;
26
+ }
27
+
28
+ // ───────────────────────────────────────────────────────── 1. carrier.mjs:67 ──
29
+
30
+ test("carrier.mjs:67 — inbox-read signature with a weak key returns 401 bad-inbox-signature", async () => {
31
+ const store = new CommonsStore();
32
+ const carrier = new CommonsCarrier({ store, trust: new RegistryTrust({ policy: { mode: "local" } }) });
33
+ const addr = await carrier.listen();
34
+ const url = `http://127.0.0.1:${addr.port}`;
35
+
36
+ try {
37
+ const res = await fetch(`${url}/v1/inbox/test-user`, {
38
+ headers: {
39
+ "x-pillar-pubkey": IDENTITY,
40
+ "x-pillar-ts": Date.now().toString(),
41
+ "x-pillar-sig": FORGED_SIG,
42
+ },
43
+ });
44
+ assert.equal(res.status, 401);
45
+ const body = await res.json();
46
+ assert.deepEqual(body, { error: "bad-inbox-signature" });
47
+ } finally {
48
+ await carrier.close();
49
+ store.close();
50
+ }
51
+ });
52
+
53
+ // ────────────────────────────────────────────── 2. carrier.mjs (C6 pole) ──
54
+
55
+ test("carrier.mjs (C6) — malformed pubkey header returns 401 bad-inbox-signature without throw", async () => {
56
+ const store = new CommonsStore();
57
+ const carrier = new CommonsCarrier({ store, trust: new RegistryTrust({ policy: { mode: "local" } }) });
58
+ const addr = await carrier.listen();
59
+ const url = `http://127.0.0.1:${addr.port}`;
60
+
61
+ try {
62
+ const res = await fetch(`${url}/v1/inbox/test-user`, {
63
+ headers: {
64
+ "x-pillar-pubkey": "not-a-valid-hex-pubkey",
65
+ "x-pillar-ts": Date.now().toString(),
66
+ "x-pillar-sig": "00".repeat(64),
67
+ },
68
+ });
69
+ assert.equal(res.status, 401);
70
+ const body = await res.json();
71
+ assert.deepEqual(body, { error: "bad-inbox-signature" });
72
+ } finally {
73
+ await carrier.close();
74
+ store.close();
75
+ }
76
+ });
77
+
78
+ // ────────────────────────────────────────────────────── 3. continuity.mjs:233 ──
79
+
80
+ test("continuity.mjs:233 — weak owner key is refused with ContinuityError INTEGRITY", () => {
81
+ const weakUuaid = `uuaid:foundation:agent:${Keychain.localIdFromKey(Buffer.from(IDENTITY, "hex"))}`;
82
+ const fakeKeychain = {
83
+ _identity: { uuaid: weakUuaid, publicKeyHex: IDENTITY },
84
+ sign: () => Buffer.from(FORGED_SIG, "hex"),
85
+ };
86
+
87
+ const store = new MemoryContinuityStore();
88
+ const entry = {
89
+ v: "agent-commons/continuity/1",
90
+ seq: 0,
91
+ id: randomUUID(),
92
+ at: new Date().toISOString(),
93
+ kind: "note",
94
+ content: { test: "data" },
95
+ provenance: { source: "self", actor: weakUuaid },
96
+ pin: false,
97
+ previous: "genesis",
98
+ hash: "",
99
+ signature: FORGED_SIG,
100
+ };
101
+ const { hash: _h, signature: _s, ...entryBody } = entry;
102
+ entry.hash = digest(entryBody);
103
+
104
+ const state = {
105
+ v: "agent-commons/continuity/1",
106
+ uuaid: weakUuaid,
107
+ publicKey: IDENTITY,
108
+ nextSeq: 1,
109
+ anchor: { previous: "genesis", pruned: 0, through: null },
110
+ entries: [entry],
111
+ sync: { lastPush: null, lastPull: null },
112
+ };
113
+ store.set(ContinuityMemory.storeKey(weakUuaid), state);
114
+
115
+ assert.throws(
116
+ () => new ContinuityMemory({ keychain: fakeKeychain, store }),
117
+ (err) => err instanceof ContinuityError && err.code === "INTEGRITY" && err.message === "Continuity entry signature invalid"
118
+ );
119
+ });
120
+
121
+ // ────────────────────────────────────────────────────── 4. governance.mjs:25 ──
122
+
123
+ test("governance.mjs:25 (C5) — weak key reaching verifyDetached is refused with INVALID_SIGNATURE", () => {
124
+ const weakUuaid = `uuaid:local:agent:${Keychain.localIdFromKey(Buffer.from(IDENTITY, "hex"))}`;
125
+ const doc = {
126
+ v: "agent-commons/1",
127
+ id: randomUUID(),
128
+ kind: "governance-proposal",
129
+ issuer: weakUuaid,
130
+ publicKey: IDENTITY,
131
+ createdAt: new Date().toISOString(),
132
+ payload: { proposal: "test-small-order-refusal" },
133
+ signature: FORGED_SIG,
134
+ };
135
+
136
+ assert.throws(
137
+ () => verifyGovernanceDocument(doc),
138
+ (err) => err instanceof GovernanceError && err.code === "INVALID_SIGNATURE"
139
+ );
140
+ });
141
+
142
+ // ──────────────────────────────────────────────────────── 5. profiles.mjs:85 ──
143
+
144
+ test("profiles.mjs:85 (C5) — weak key reaching verifyDetached is refused with Invalid document signature", () => {
145
+ const weakUuaid = `uuaid:local:agent:${Keychain.localIdFromKey(Buffer.from(IDENTITY, "hex"))}`;
146
+ const doc = {
147
+ v: "agent-commons/1",
148
+ id: randomUUID(),
149
+ kind: "profile-proposal",
150
+ issuer: weakUuaid,
151
+ publicKey: IDENTITY,
152
+ createdAt: new Date().toISOString(),
153
+ payload: { proposal: "test-profile-refusal" },
154
+ signature: FORGED_SIG,
155
+ };
156
+
157
+ assert.throws(
158
+ () => verifyDocument(doc),
159
+ (err) => err instanceof Error && err.message === "Invalid document signature"
160
+ );
161
+ });
162
+
163
+ // ─────────────────────────────────────────── 6. runtime.mjs:162 (CONTROL) ──
164
+
165
+ test("runtime.mjs:162 (CONTROL) — honest outbox metadata signature verification succeeds on flush", async () => {
166
+ const senderKey = makeKey();
167
+ const recipientKey = makeKey();
168
+ const transport = new MemoryLoopbackTransport();
169
+
170
+ const runtime = new AgentCommons({
171
+ keychain: senderKey,
172
+ policy: {
173
+ mode: "local",
174
+ agents: {
175
+ [senderKey._identity.uuaid]: {
176
+ kind: "agent",
177
+ publicKey: senderKey._identity.publicKeyHex,
178
+ capabilities: ["commons:message"],
179
+ },
180
+ [recipientKey._identity.uuaid]: {
181
+ kind: "agent",
182
+ publicKey: recipientKey._identity.publicKeyHex,
183
+ capabilities: ["commons:message"],
184
+ },
185
+ },
186
+ },
187
+ transport,
188
+ });
189
+
190
+ const { createProfile } = await import("../src/profiles.mjs");
191
+ const profile = createProfile({
192
+ namespace: "test/fleet",
193
+ name: "Fixture profile",
194
+ scope: "local",
195
+ fixtures: ["Require semantic equivalence and semantic equivalence.", "Preserve semantic equivalence before accepting a profile."],
196
+ });
197
+ runtime.addProfile(profile);
198
+
199
+ const sent = await runtime.send({
200
+ recipient: recipientKey._identity.uuaid,
201
+ profileId: profile.id,
202
+ body: "test-honest-runtime-flush",
203
+ });
204
+
205
+ assert.equal(sent.result[0].state, "carrier-accepted");
206
+ assert.equal(sent.result[0].receipt.accepted, true);
207
+ runtime.store.close();
208
+ });
209
+
210
+ // ───────────────────────────────────────────────────────────── 7. open() ──
211
+
212
+ test("open() — forged envelope with small-order public key is refused with weak-publicKey", () => {
213
+ const recipientKey = makeKey();
214
+ const honest = seal(makeKey(), {
215
+ recipient: recipientKey._identity.uuaid,
216
+ recipientPublicKey: recipientKey._identity.publicKeyHex,
217
+ payload: { text: "forged" },
218
+ });
219
+ const sender = `uuaid:foundation:agent:${Keychain.localIdFromKey(Buffer.from(IDENTITY, "hex"))}`;
220
+ const { transportSignature: _s, ...body } = honest;
221
+ const forged = {
222
+ ...body,
223
+ sender,
224
+ transportSignature: {
225
+ alg: "ed25519",
226
+ keyId: sender,
227
+ publicKey: IDENTITY,
228
+ signature: FORGED_SIG,
229
+ created: body.createdAt,
230
+ },
231
+ };
232
+
233
+ assert.deepEqual(open(forged), { ok: false, reason: "weak-publicKey" });
234
+ });