code wiki / _hdl_build / nx_legal_portal_post_gate.nx
nx_legal_portal_post_gate.nx source
↩ module page · 164 lines · 7434 B
1// nx_legal_portal_post_gate.nx -- GATE for the interactive POST routes (lp_handle_post), ENGINEER verify.
2//
3// Proves the portal's MUTATING actions over HTTP (the markup/checklist interactivity),
4// composing D4 (annotate) + D8 (persist), each with a control:
5// T1 POST annotate : POST /portal/annotate adds a note -> 200, store grows
6// T2 POST check : add a required checklist item then POST /portal/check?ann= ->
7// the item is DONE (GET /portal/checklist -> remaining 0 READY)
8// T3 MUTATION PERSISTS : after the POSTs, save + reload into FRESH arrays -> the
9// checklist done-state + the note survive (durable interactivity)
10// T4 AUTHZ : POST to /staff at level 1 -> 403 ; unknown path -> 404
11// T5 NEG : POST /portal/annotate with no doc -> 400 (not silent)
12//
13// lp_handle (GET) is UNCHANGED -- the POST router is a new function, so the existing
14// portal GET gates are not regressed (re-verified separately).
15//
16// Evidence -> knowledge/status/legal_portal_post.log
17// license_tier: ORIGINAL
18import "nx_legal_portal.nx"
19import "nx_legal_portal_boot.nx"
20import "nx_doc_annotate.nx"
21import "nx_doc_envelope.nx"
22import "nx_doc_vault.nx"
23import "nx_legal_compliance.nx"
24import "nx_syscalls.nx"
25
26const LPP_LOG: *u8 = "knowledge/status/legal_portal_post.log"
27const LPP_BASE: *u8 = "/tmp/nx_lpp_"
28
29func ew(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 }
30func ewn(fd: i64, v: i64) -> i64 {
31 let bb: *u8 = sys_mmap(28); var m: i64 = v
32 if m < 0 { m = 0 - m; sys_write(fd, "-" as *u8, 1) }
33 let t: *u8 = sys_mmap(28); var k: i64 = 0
34 if m == 0 { t[0] = 48; k = 1 }
35 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
36 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
37 sys_write(fd, bb, k); return 0
38}
39func slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
40func g_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { d[o + i] = s[i]; i = i + 1 } return o + i }
41func g_starts(buf: *u8, n: i64, s: *u8) -> i64 {
42 let sn: i64 = slen(s)
43 if n < sn { return 0 }
44 var i: i64 = 0
45 while i < sn { if buf[i] != s[i] { return 0 } i = i + 1 }
46 return 1
47}
48func g_contains(hay: *u8, n: i64, needle: *u8) -> i64 {
49 let nn: i64 = slen(needle)
50 if nn == 0 { return 1 }
51 var i: i64 = 0
52 while i + nn <= n {
53 var m: i64 = 1
54 var j: i64 = 0
55 while j < nn { if hay[i + j] != needle[j] { m = 0; break } j = j + 1 }
56 if m == 1 { return 1 }
57 i = i + 1
58 }
59 return 0
60}
61
62func main() -> i64 {
63 var ok: i64 = 1
64 let ncap: i64 = 16
65 let vcap: i64 = 8
66 let ecap: i64 = 8
67 let rcap: i64 = 8
68 let eflat: *i64 = sys_mmap(ecap * EF_STRIDE * 8) as *i64
69 let rflat: *i64 = sys_mmap(rcap * RF_STRIDE * 8) as *i64
70 let anflat: *i64 = sys_mmap(ncap * NF_STRIDE * 8) as *i64
71 let vflat: *i64 = sys_mmap(vcap * VF_STRIDE * 8) as *i64
72 let eidbuf: *i64 = sys_mmap(32) as *i64
73 var vc: i64 = nx_vault_add(vflat, 0, vcap, 8601, 5001, 64, 1000)
74
75 let ctx: *NxPortalCtx = sys_mmap(256) as *NxPortalCtx
76 ctx.user_level = 1
77 ctx.eflat = eflat; ctx.ne = 0
78 ctx.rflat = rflat; ctx.nr = 0
79 ctx.anflat = anflat; ctx.na = 0
80 ctx.vflat = vflat; ctx.vc = vc
81 ctx.env_ids = eidbuf; ctx.env_count = 0
82
83 let req: *u8 = sys_mmap(4096)
84 let out: *u8 = sys_mmap(16384)
85
86 // ---- T1: POST annotate adds a note ----
87 var t1: i64 = 1
88 var rn: i64 = g_cat(req, 0, "POST /portal/annotate?doc=8601&ann=50&author=700&typ=0 HTTP/1.1\r\nHost: x\r\n\r\n" as *u8)
89 var on: i64 = lp_handle_post(ctx, ncap, req, rn, out)
90 if g_starts(out, on, "HTTP/1.1 200" as *u8) != 1 { t1 = 0 }
91 if g_contains(out, on, "ANNOTATED doc 8601 ann 50" as *u8) != 1 { t1 = 0 }
92 if nx_ann_count(anflat, ctx.na, 8601, 1) != 1 { t1 = 0 }
93 if t1 != 1 { ok = 0 }
94
95 // ---- T2: POST add a required checklist item, then POST check it done ----
96 var t2: i64 = 1
97 rn = g_cat(req, 0, "POST /portal/annotate?doc=8601&ann=60&author=700&typ=4&req=1 HTTP/1.1\r\nHost: x\r\n\r\n" as *u8)
98 on = lp_handle_post(ctx, ncap, req, rn, out)
99 if g_starts(out, on, "HTTP/1.1 200" as *u8) != 1 { t2 = 0 }
100 if nx_ann_checklist_remaining(anflat, ctx.na, 8601, 1) != 1 { t2 = 0 } // pending
101 rn = g_cat(req, 0, "POST /portal/check?ann=60 HTTP/1.1\r\nHost: x\r\n\r\n" as *u8)
102 on = lp_handle_post(ctx, ncap, req, rn, out)
103 if g_starts(out, on, "HTTP/1.1 200" as *u8) != 1 { t2 = 0 }
104 if g_contains(out, on, "CHECKED ann 60" as *u8) != 1 { t2 = 0 }
105 // GET the checklist via lp_handle -> now READY
106 rn = g_cat(req, 0, "GET /portal/checklist?doc=8601 HTTP/1.1\r\nHost: x\r\n\r\n" as *u8)
107 on = lp_handle(ctx, req, rn, out)
108 if g_contains(out, on, "remaining 0 READY" as *u8) != 1 { t2 = 0 }
109 if t2 != 1 { ok = 0 }
110
111 // ---- T3: the mutations PERSIST across a reboot ----
112 var t3: i64 = 1
113 lp_boot_save(ctx, LPP_BASE, "clientA" as *u8)
114 let anflat2: *i64 = sys_mmap(ncap * NF_STRIDE * 8) as *i64
115 let eflat2: *i64 = sys_mmap(ecap * EF_STRIDE * 8) as *i64
116 let rflat2: *i64 = sys_mmap(rcap * RF_STRIDE * 8) as *i64
117 let vflat2: *i64 = sys_mmap(vcap * VF_STRIDE * 8) as *i64
118 let eidbuf2: *i64 = sys_mmap(32) as *i64
119 let ctx2: *NxPortalCtx = sys_mmap(256) as *NxPortalCtx
120 ctx2.user_level = 1
121 lp_boot_load(ctx2, LPP_BASE, "clientA" as *u8, eflat2, ecap, rflat2, rcap, anflat2, ncap, vflat2, vcap, eidbuf2)
122 if nx_ann_count(anflat2, ctx2.na, 8601, 1) != 2 { t3 = 0 } // note + check persisted
123 rn = g_cat(req, 0, "GET /portal/checklist?doc=8601 HTTP/1.1\r\nHost: x\r\n\r\n" as *u8)
124 on = lp_handle(ctx2, req, rn, out)
125 if g_contains(out, on, "remaining 0 READY" as *u8) != 1 { t3 = 0 } // done-state persisted
126 if t3 != 1 { ok = 0 }
127
128 // ---- T4: authz ----
129 var t4: i64 = 1
130 rn = g_cat(req, 0, "POST /staff/x HTTP/1.1\r\nHost: x\r\n\r\n" as *u8)
131 on = lp_handle_post(ctx, ncap, req, rn, out)
132 if g_starts(out, on, "HTTP/1.1 403" as *u8) != 1 { t4 = 0 }
133 rn = g_cat(req, 0, "POST /portal/bogus HTTP/1.1\r\nHost: x\r\n\r\n" as *u8)
134 on = lp_handle_post(ctx, ncap, req, rn, out)
135 if g_starts(out, on, "HTTP/1.1 404" as *u8) != 1 { t4 = 0 }
136 if t4 != 1 { ok = 0 }
137
138 // ---- T5: NEG -- missing doc -> 400 ----
139 var t5: i64 = 1
140 rn = g_cat(req, 0, "POST /portal/annotate?ann=99 HTTP/1.1\r\nHost: x\r\n\r\n" as *u8)
141 on = lp_handle_post(ctx, ncap, req, rn, out)
142 if g_starts(out, on, "HTTP/1.1 400" as *u8) != 1 { t5 = 0 }
143 if t5 != 1 { ok = 0 }
144
145 // ---- evidence ----
146 var fd: i64 = 1
147 while fd >= 1 {
148 ew(fd, "LEGALPORTALPOSTGATE authored=organ composes=D4+D8 post_annotate=" as *u8); ewn(fd, t1)
149 ew(fd, " post_check_done=" as *u8); ewn(fd, t2)
150 ew(fd, " mutation_persists=" as *u8); ewn(fd, t3)
151 ew(fd, " authz=" as *u8); ewn(fd, t4)
152 ew(fd, " neg_missing_doc=" as *u8); ewn(fd, t5)
153 if ok == 1 { ew(fd, " verdict=GREEN\n" as *u8) } else { ew(fd, " verdict=RED\n" as *u8) }
154 if fd == 1 {
155 let lf: i64 = sys_openat_append(LPP_LOG, 420)
156 if lf >= 1 { fd = lf } else { fd = 0 }
157 } else {
158 sys_close(fd); fd = 0
159 }
160 }
161
162 if ok == 1 { return 0 }
163 return 1
164}