code wiki / _hdl_build / nx_connect_accounts_gate.nx

nx_connect_accounts_gate.nx source

↩ module page · 126 lines · 6057 B

1// nx_connect_accounts_gate.nx -- gate for CONNECT accounts + persistence (nx_connect_accounts). Uses 2// REAL disk I/O (writes to /tmp/connacc): proves a per-account world survives save->reload, that two 3// accounts are ISOLATED (A can never read B), that a missing account loads the fresh seed, and that a 4// tampered snapshot is rejected (fail-closed). license_tier: ORIGINAL expect_exit: 0 5import "nx_connect_accounts.nx" 6 7func ag_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 8func ag_n(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1} sys_write(1,bb,k); return 0 } 9func ag_check(pass: i64, label: *u8, fails: *i64) -> i64 { 10 ag_w(" " as *u8); ag_w(label); ag_w(": " as *u8) 11 if pass==1 { ag_w("PASS\n" as *u8) } else { ag_w("FAIL\n" as *u8); fails[0]=fails[0]+1 } 12 return 0 13} 14func ag_addmsg(ctx: *i64, speaker: i64, text: *u8) -> i64 { 15 let k: i64 = ctx[CS_NMSG] 16 if k >= CS_MSGCAP { return 0 } 17 let spk: *i64 = ctx[CS_SPK] as *i64 18 let txt: *u8 = ctx[CS_TXTA] as *u8 19 spk[k] = speaker 20 var w: i64 = 0 21 while text[w] != (0 as u8) { txt[k*CS_TXT+w] = text[w]; w = w + 1 } 22 txt[k*CS_TXT+w] = 0 as u8 23 ctx[CS_NMSG] = k + 1 24 return 1 25} 26// does message i of ctx equal want? 27func ag_msg_eq(ctx: *i64, i: i64, want: *u8) -> i64 { 28 let txt: *u8 = ctx[CS_TXTA] as *u8 29 var w: i64 = 0 30 while want[w] != (0 as u8) { if txt[i*CS_TXT+w] != want[w] { return 0 } w = w + 1 } 31 if txt[i*CS_TXT+w] != (0 as u8) { return 0 } 32 return 1 33} 34// is `want` present as ANY message in ctx? 35func ag_has_msg(ctx: *i64, want: *u8) -> i64 { 36 var i: i64 = 0 37 while i < ctx[CS_NMSG] { if ag_msg_eq(ctx, i, want) == 1 { return 1 } i = i + 1 } 38 return 0 39} 40 41func main() -> i64 { 42 let fails: *i64 = sys_mmap(16) as *i64 43 fails[0]=0 44 ag_w("=== nx_connect_accounts_gate -- per-account CONNECT persistence (real disk, isolated) ===\n" as *u8) 45 let dir: *u8 = "/tmp/connacc\x00" as *u8 46 sys_mkdir(dir, 0x1ff) 47 48 // ---- T1: save a world, reload into a FRESH world -> identical ---- 49 let a: *i64 = cs_world_new() 50 ag_addmsg(a, 1, "vera alpha message" as *u8) 51 a[8] = 2 // poll vote = Riverside 52 a[CS_EV1_GOING] = 5 53 let idA: i64 = acc_id_from_handle("alice" as *u8) 54 let sn: i64 = acc_save(a, idA, dir) 55 let a2: *i64 = cs_world_new() 56 let lr: i64 = acc_load(a2, idA, dir) 57 var t1: i64=0 58 if sn > 0 { if lr == 1 { 59 if a2[CS_NMSG] == a[CS_NMSG] { if ag_has_msg(a2, "vera alpha message" as *u8) == 1 { 60 if a2[8] == 2 { if a2[CS_EV1_GOING] == 5 { t1 = 1 } } } } 61 } } 62 ag_w(" saved " as *u8); ag_n(sn); ag_w("B; reloaded nmsg=" as *u8); ag_n(a2[CS_NMSG]); ag_w("\n" as *u8) 63 ag_check(t1, "T1 world saved + reloaded into a fresh world: messages + poll + event state intact" as *u8, fails) 64 65 // ---- T2: ISOLATION -- two accounts, each reads only its own ---- 66 let b: *i64 = cs_world_new() 67 ag_addmsg(b, 0, "you bravo message" as *u8) 68 let idB: i64 = acc_id_from_handle("bob" as *u8) 69 acc_save(b, idB, dir) 70 let ra: *i64 = cs_world_new() 71 acc_load(ra, idA, dir) 72 let rb: *i64 = cs_world_new() 73 acc_load(rb, idB, dir) 74 var t2: i64=0 75 if ag_has_msg(ra, "vera alpha message" as *u8) == 1 { 76 if ag_has_msg(ra, "you bravo message" as *u8) == 0 { // A cannot see B 77 if ag_has_msg(rb, "you bravo message" as *u8) == 1 { 78 if ag_has_msg(rb, "vera alpha message" as *u8) == 0 { t2 = 1 } // B cannot see A 79 } 80 } 81 } 82 ag_check(t2, "T2 isolation: account A reads only A's messages; B only B's (id in path, by construction)" as *u8, fails) 83 84 // ---- T3: missing account -> loads the FRESH seed (returns 0, world untouched) ---- 85 let c: *i64 = cs_world_new() 86 let seed_n: i64 = c[CS_NMSG] // the seeded 2 messages 87 let mr: i64 = acc_load(c, acc_id_from_handle("nobody-here" as *u8), dir) 88 var t3: i64=0 89 if mr == 0 { if c[CS_NMSG] == seed_n { t3 = 1 } } 90 ag_check(t3, "T3 missing account: load returns 0, world keeps its fresh seed (no crash)" as *u8, fails) 91 92 // ---- T4: idempotent re-save (save twice -> same reload) ---- 93 acc_save(a, idA, dir) 94 acc_save(a, idA, dir) 95 let a3: *i64 = cs_world_new() 96 acc_load(a3, idA, dir) 97 var t4: i64=0 98 if a3[CS_NMSG] == a[CS_NMSG] { if ag_has_msg(a3, "vera alpha message" as *u8) == 1 { t4 = 1 } } 99 ag_check(t4, "T4 idempotent re-save: twice-saved account reloads identically" as *u8, fails) 100 101 // ---- T5: NEG -- a tampered snapshot (bad magic) is REJECTED, world not corrupted ---- 102 let bad: *u8 = sys_mmap(64) 103 var z: i64=0 104 while z < 40 { bad[z] = 0x5a as u8; z = z + 1 } // garbage, wrong magic 105 let d: *i64 = cs_world_new() 106 let dn0: i64 = d[CS_NMSG] 107 let dr: i64 = acc_deserialize(d, bad, 40) 108 var t5: i64=0 109 if dr == 0 { if d[CS_NMSG] == dn0 { t5 = 1 } } 110 ag_check(t5, "T5 NEG-CONTROL tampered snapshot (bad magic) rejected; world untouched (fail-closed)" as *u8, fails) 111 112 // ---- T6: distinct account_ids -> distinct files (no collision) ---- 113 var t6: i64=0 114 if idA != idB { let p1: *u8 = sys_mmap(512); let p2: *u8 = sys_mmap(512) 115 acc_path(dir, idA, p1); acc_path(dir, idB, p2) 116 var diff: i64=0; var i: i64=0 117 while p1[i] != (0 as u8) { if p1[i] != p2[i] { diff = 1 } i = i + 1 } 118 if diff == 1 { t6 = 1 } } 119 ag_check(t6, "T6 distinct handles -> distinct account_ids -> distinct snapshot paths" as *u8, fails) 120 121 ag_w(" fails=" as *u8); ag_n(fails[0]); ag_w("\n" as *u8) 122 if fails[0]==0 { ag_w("VERDICT: GREEN (per-account CONNECT state persists across restart + isolated by construction; fail-closed on tamper)\n" as *u8); sys_exit(0) } 123 ag_w("VERDICT: RED\n" as *u8) 124 sys_exit(1) 125 return 1 126}