code wiki / _hdl_build / nx_legal_portal_post_gate.nx

nx_legal_portal_post_gate.nx source

↩ module page · 172 lines · 7977 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" 25import "nx_gate_verdict.nx" 26 27const LPP_LOG: *u8 = "knowledge/status/legal_portal_post.log" 28const LPP_BASE: *u8 = "/tmp/nx_lpp_" 29 30func 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 } 31func ewn(fd: i64, v: i64) -> i64 { 32 let bb: *u8 = sys_mmap(28); var m: i64 = v 33 if m < 0 { m = 0 - m; sys_write(fd, "-" as *u8, 1) } 34 let t: *u8 = sys_mmap(28); var k: i64 = 0 35 if m == 0 { t[0] = 48; k = 1 } 36 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 37 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 38 sys_write(fd, bb, k); return 0 39} 40func slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 41func 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 } 42func g_starts(buf: *u8, n: i64, s: *u8) -> i64 { 43 let sn: i64 = slen(s) 44 if n < sn { return 0 } 45 var i: i64 = 0 46 while i < sn { if buf[i] != s[i] { return 0 } i = i + 1 } 47 return 1 48} 49func g_contains(hay: *u8, n: i64, needle: *u8) -> i64 { 50 let nn: i64 = slen(needle) 51 if nn == 0 { return 1 } 52 var i: i64 = 0 53 while i + nn <= n { 54 var m: i64 = 1 55 var j: i64 = 0 56 while j < nn { if hay[i + j] != needle[j] { m = 0; break } j = j + 1 } 57 if m == 1 { return 1 } 58 i = i + 1 59 } 60 return 0 61} 62 63func main() -> i64 { 64 var ok: i64 = 1 65 let ncap: i64 = 16 66 let vcap: i64 = 8 67 let ecap: i64 = 8 68 let rcap: i64 = 8 69 let eflat: *i64 = sys_mmap(ecap * EF_STRIDE * 8) as *i64 70 let rflat: *i64 = sys_mmap(rcap * RF_STRIDE * 8) as *i64 71 let anflat: *i64 = sys_mmap(ncap * NF_STRIDE * 8) as *i64 72 let vflat: *i64 = sys_mmap(vcap * VF_STRIDE * 8) as *i64 73 let eidbuf: *i64 = sys_mmap(32) as *i64 74 var vc: i64 = nx_vault_add(vflat, 0, vcap, 8601, 5001, 64, 1000) 75 76 let ctx: *NxPortalCtx = sys_mmap(256) as *NxPortalCtx 77 ctx.user_level = 1 78 ctx.eflat = eflat; ctx.ne = 0 79 ctx.rflat = rflat; ctx.nr = 0 80 ctx.anflat = anflat; ctx.na = 0 81 ctx.vflat = vflat; ctx.vc = vc 82 ctx.env_ids = eidbuf; ctx.env_count = 0 83 84 let req: *u8 = sys_mmap(4096) 85 let out: *u8 = sys_mmap(16384) 86 87 // ---- T1: POST annotate adds a note ---- 88 var t1: i64 = 1 89 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) 90 var on: i64 = lp_handle_post(ctx, ncap, req, rn, out) 91 if g_starts(out, on, "HTTP/1.1 200" as *u8) != 1 { t1 = 0 } 92 if g_contains(out, on, "ANNOTATED doc 8601 ann 50" as *u8) != 1 { t1 = 0 } 93 if nx_ann_count(anflat, ctx.na, 8601, 1) != 1 { t1 = 0 } 94 if t1 != 1 { ok = 0 } 95 96 // ---- T2: POST add a required checklist item, then POST check it done ---- 97 var t2: i64 = 1 98 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) 99 on = lp_handle_post(ctx, ncap, req, rn, out) 100 if g_starts(out, on, "HTTP/1.1 200" as *u8) != 1 { t2 = 0 } 101 if nx_ann_checklist_remaining(anflat, ctx.na, 8601, 1) != 1 { t2 = 0 } // pending 102 rn = g_cat(req, 0, "POST /portal/check?ann=60 HTTP/1.1\r\nHost: x\r\n\r\n" as *u8) 103 on = lp_handle_post(ctx, ncap, req, rn, out) 104 if g_starts(out, on, "HTTP/1.1 200" as *u8) != 1 { t2 = 0 } 105 if g_contains(out, on, "CHECKED ann 60" as *u8) != 1 { t2 = 0 } 106 // GET the checklist via lp_handle -> now READY 107 rn = g_cat(req, 0, "GET /portal/checklist?doc=8601 HTTP/1.1\r\nHost: x\r\n\r\n" as *u8) 108 on = lp_handle(ctx, req, rn, out) 109 if g_contains(out, on, "remaining 0 READY" as *u8) != 1 { t2 = 0 } 110 if t2 != 1 { ok = 0 } 111 112 // ---- T3: the mutations PERSIST across a reboot ---- 113 var t3: i64 = 1 114 lp_boot_save(ctx, LPP_BASE, "clientA" as *u8) 115 let anflat2: *i64 = sys_mmap(ncap * NF_STRIDE * 8) as *i64 116 let eflat2: *i64 = sys_mmap(ecap * EF_STRIDE * 8) as *i64 117 let rflat2: *i64 = sys_mmap(rcap * RF_STRIDE * 8) as *i64 118 let vflat2: *i64 = sys_mmap(vcap * VF_STRIDE * 8) as *i64 119 let eidbuf2: *i64 = sys_mmap(32) as *i64 120 let ctx2: *NxPortalCtx = sys_mmap(256) as *NxPortalCtx 121 ctx2.user_level = 1 122 lp_boot_load(ctx2, LPP_BASE, "clientA" as *u8, eflat2, ecap, rflat2, rcap, anflat2, ncap, vflat2, vcap, eidbuf2) 123 if nx_ann_count(anflat2, ctx2.na, 8601, 1) != 2 { t3 = 0 } // note + check persisted 124 rn = g_cat(req, 0, "GET /portal/checklist?doc=8601 HTTP/1.1\r\nHost: x\r\n\r\n" as *u8) 125 on = lp_handle(ctx2, req, rn, out) 126 if g_contains(out, on, "remaining 0 READY" as *u8) != 1 { t3 = 0 } // done-state persisted 127 if t3 != 1 { ok = 0 } 128 129 // ---- T4: authz ---- 130 var t4: i64 = 1 131 rn = g_cat(req, 0, "POST /staff/x HTTP/1.1\r\nHost: x\r\n\r\n" as *u8) 132 on = lp_handle_post(ctx, ncap, req, rn, out) 133 if g_starts(out, on, "HTTP/1.1 403" as *u8) != 1 { t4 = 0 } 134 rn = g_cat(req, 0, "POST /portal/bogus HTTP/1.1\r\nHost: x\r\n\r\n" as *u8) 135 on = lp_handle_post(ctx, ncap, req, rn, out) 136 if g_starts(out, on, "HTTP/1.1 404" as *u8) != 1 { t4 = 0 } 137 if t4 != 1 { ok = 0 } 138 139 // ---- T5: NEG -- missing doc -> 400 ---- 140 var t5: i64 = 1 141 rn = g_cat(req, 0, "POST /portal/annotate?ann=99 HTTP/1.1\r\nHost: x\r\n\r\n" as *u8) 142 on = lp_handle_post(ctx, ncap, req, rn, out) 143 if g_starts(out, on, "HTTP/1.1 400" as *u8) != 1 { t5 = 0 } 144 if t5 != 1 { ok = 0 } 145 146 // ---- evidence ---- 147 var fd: i64 = 1 148 while fd >= 1 { 149 ew(fd, "LEGALPORTALPOSTGATE authored=organ composes=D4+D8 post_annotate=" as *u8); ewn(fd, t1) 150 ew(fd, " post_check_done=" as *u8); ewn(fd, t2) 151 ew(fd, " mutation_persists=" as *u8); ewn(fd, t3) 152 ew(fd, " authz=" as *u8); ewn(fd, t4) 153 ew(fd, " neg_missing_doc=" as *u8); ewn(fd, t5) 154 if ok == 1 { ew(fd, " verdict=GREEN\n" as *u8) } else { ew(fd, " verdict=RED\n" as *u8) } 155 if fd == 1 { 156 let lf: i64 = sys_openat_append(LPP_LOG, 420) 157 if lf >= 1 { fd = lf } else { fd = 0 } 158 } else { 159 sys_close(fd); fd = 0 160 } 161 } 162 163 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 164 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 165 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 166 let ctr__dry: *i64 = gv_ctr() 167 ctr__dry[0] = ok 168 ctr__dry[1] = 1 169 let rc__dry: i64 = gv_verdict("LEGAL-PORTAL-POST-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 170 sys_exit(rc__dry) 171 return rc__dry 172}