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}