code wiki / (root) / nx_browser_gate.nx

nx_browser_gate.nx source

↩ module page · 285 lines · 11357 B

1// nx_browser_gate.nx -- THE BROWSER GATE: one command re-proves the 2// Nishi browser claim set, evidence-driven + durable. 3// 4// Data-driven row table (add a row = add a table entry). Each row 5// names a runtime/<module>.nx; the gate compiles it with the NATIVE 6// browser-lane compiler (_offc/nx_compile_x86_native.elf), assembles 7// + links, runs the ELF, and judges via the RAW wait4 status (the 8// sovereign exit-judging law -- never $? through a shell). 9// 10// Rows (the browser claim set, 2026-06-10): 11// arg7-tailcall compiler regression gate: >6-arg tail-call drop 12// (the defect that zeroed every TLS Derive-Secret) 13// tls-kdf RFC 8448 Derive-Secret KATs 14// tls-schedule TLS 1.3 key-schedule KATs 15// jpeg-ascii deterministic synthetic-JPEG decode + raster 16// page-demo live HTTP fetch + html_to_text (example.com:80) 17// own-site-live LIVE sovereign HTTPS fetch of nishifamily.com 18// (TLS 1.3 + real Mozilla CA chain validation) 19// render-own paints the FETCHED page's text -> framebuffer 20// (consumes own-site-live's /tmp/nishi_own.html) 21// recv-hs-probe B1 rung: full encrypted-handshake walk vs 22// example.com (per-record/per-message markers, 23// cert-pipeline verdict + chain sig-alg census); 24// exit 0 = handshake to WAIT_CLIENT_FIN 25// p256-keyshare B4 rung: P-256 ECDH (RFC 5903 KAT both 26// directions, boundary rejects) + dual key_share 27// wire format (x25519 + secp256r1 in one CH) 28// derefcast compiler regression gate: `*p as T` precedence 29// (pre-fix: cast bound inside the deref -> byte- 30// load of the pointer cell -> SIGSEGV; fixed in 31// parse_unary 2026-06-10) 32// p256-loopback B4 server side: OUR server completes a P-256-only 33// client (no HRR), both roles derive byte-identical 34// traffic secrets, off-curve share rejected (the 35// nishifamily P-256 gap, healed + loopback-proven) 36// ch-compat B2 rung, two live legs: httpbin.org census 37// (TLS-1.2-only signature classified -- the CH 38// was never the defect; auto-escalates to a full 39// handshake if they enable 1.3) + github.com 40// P-256-only CH walked to verified server 41// Finished (GR=23: live proof of the B4 path) 42// 43// Verdict lines stream to stdout AND append to the durable log 44// knowledge/status/browser_gate.log (Archivist durability rule -- 45// /tmp dies on reboot, knowledge/ does not). 46// 47// Exit 0 iff every row passes. ORCHESTRATION is pure NishiLang 48// fork/dup3/execve/wait4 -- NO shell, NO .sh. 49// 50// license_tier: ORIGINAL 51 52import "nx_syscalls.nx" 53import "nx_gate_verdict.nx" 54 55const BG_ROWS: i64 = 12 56 57func bg_puts(s: *u8) -> i64 { 58 var n: i64 = 0 59 while s[n] != (0 as u8) { n = n + 1 } 60 sys_write(1, s, n) 61 return 0 62} 63 64func bg_fputs(fd: i64, s: *u8) -> i64 { 65 var n: i64 = 0 66 while s[n] != (0 as u8) { n = n + 1 } 67 sys_write(fd, s, n) 68 return 0 69} 70 71func bg_fputn(fd: i64, v: i64) -> i64 { 72 let bb: *u8 = sys_mmap(28) 73 var m: i64 = v 74 if m < 0 { m = 0 - m; sys_write(fd, "-" as *u8, 1) } 75 let t: *u8 = sys_mmap(28) 76 var k: i64 = 0 77 if m == 0 { t[0] = 48 as u8; k = 1 } 78 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 79 var i: i64 = 0 80 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 81 sys_write(fd, bb, k) 82 return 0 83} 84 85func bg_putn(v: i64) -> i64 { bg_fputn(1, v); return 0 } 86 87func bg_cat(dst: *u8, off: i64, s: *u8) -> i64 { 88 var i: i64 = 0 89 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 } 90 return off + i 91} 92 93// fork + redirects + execve; parent waits; returns RAW wait status. 94func bg_run(path: *u8, argv: *i64, envp: *i64, redir_out: i64, redir_err: i64) -> i64 { 95 let pid: i64 = sys_fork() 96 if pid == 0 { 97 if redir_out >= 0 { sys_dup3(redir_out, 1, 0) } 98 if redir_err >= 0 { sys_dup3(redir_err, 2, 0) } 99 sys_execve(path, argv, envp) 100 sys_exit(127) 101 } 102 let st: *i64 = sys_mmap(16) as *i64 103 sys_wait4(pid, st, 0) 104 return st[0] 105} 106 107// Compile runtime/<mod>.nx -> /tmp/bg_row.elf via native lane. 108// Returns 0 ok, 1 compile-fail, 2 as-fail, 3 ld-fail. 109func bg_build(mod: *u8, envp: *i64, devnull: i64) -> i64 { 110 let src: *u8 = sys_mmap(512) 111 var o: i64 = 0 112 o = bg_cat(src, o, "runtime/\x00" as *u8) 113 o = bg_cat(src, o, mod) 114 o = bg_cat(src, o, ".nx\x00" as *u8) 115 src[o] = 0 as u8 116 117 let cc: *u8 = "_offc/nx_compile_x86_native.elf\x00" 118 let a1: *i64 = sys_mmap(8 * 4) as *i64 119 a1[0] = cc as i64; a1[1] = src as i64; a1[2] = 0 120 let sfd: i64 = sys_openat_wr("/tmp/bg_row.s\x00", 0x1a4) 121 let st1: i64 = bg_run(cc, a1, envp, sfd, devnull) 122 sys_close(sfd) 123 if st1 != 0 { return 1 } 124 125 let asbin: *u8 = "/usr/bin/as\x00" 126 let a2: *i64 = sys_mmap(8 * 6) as *i64 127 a2[0] = asbin as i64 128 a2[1] = "/tmp/bg_row.s\x00" as *u8 as i64 129 a2[2] = "-o\x00" as *u8 as i64 130 a2[3] = "/tmp/bg_row.o\x00" as *u8 as i64 131 a2[4] = 0 132 if bg_run(asbin, a2, envp, 0 - 1, devnull) != 0 { return 2 } 133 134 let ldbin: *u8 = "/usr/bin/ld\x00" 135 let a3: *i64 = sys_mmap(8 * 6) as *i64 136 a3[0] = ldbin as i64 137 a3[1] = "/tmp/bg_row.o\x00" as *u8 as i64 138 a3[2] = "-o\x00" as *u8 as i64 139 a3[3] = "/tmp/bg_row.elf\x00" as *u8 as i64 140 a3[4] = 0 141 if bg_run(ldbin, a3, envp, 0 - 1, devnull) != 0 { return 3 } 142 return 0 143} 144 145// Emit one row verdict to stdout + durable log. 146func bg_report(logfd: i64, name: *u8, build_rc: i64, exit_code: i64, sig: i64, pass: i64) -> i64 { 147 var fdi: i64 = 0 148 while fdi < 2 { 149 var fd: i64 = 1 150 if fdi == 1 { fd = logfd } 151 if fd > 0 { 152 bg_fputs(fd, "BROWSER-GATE row=\x00" as *u8) 153 bg_fputs(fd, name) 154 bg_fputs(fd, " build=\x00" as *u8) 155 bg_fputn(fd, build_rc) 156 bg_fputs(fd, " exit=\x00" as *u8) 157 bg_fputn(fd, exit_code) 158 bg_fputs(fd, " sig=\x00" as *u8) 159 bg_fputn(fd, sig) 160 if pass == 1 { bg_fputs(fd, " verdict=PASS\n\x00" as *u8) } 161 if pass != 1 { bg_fputs(fd, " verdict=FAIL\n\x00" as *u8) } 162 } 163 fdi = fdi + 1 164 } 165 return 0 166} 167 168// Stage the real Mozilla CA bundle from the DURABLE repo copy into /tmp. 169// tmpfs dies on every reboot (proven 2026-06-10: crash wiped it and turned 170// own-site-live + render-own RED); knowledge/ does not -- Archivist rule. 171// 172// ALWAYS restage (idempotent, rule 10): the old "size>1MB -> skip" check 173// refused to refresh a STALE-but-large /tmp bundle, so once a rotted bundle 174// sat in /tmp the live-TLS rows rotted with it -- this was the entire 175// "TLS-FIN bedrock regression" (2026-06-13: stale /tmp bundle drove 176// recv_hs_probe exit=44 + ch_compat exit=144 while example.com/github.com 177// validated fine against the fresh durable bundle). /tmp now ends byte-equal 178// to knowledge/ every run; the reported byte count also makes freshness 179// self-evident in the log instead of a silent "bytes=0". 180// Returns bytes staged, negative on missing/unwritable target. 181func bg_stage_certdata() -> i64 { 182 let src: i64 = sys_openat_rd("knowledge/library/mozilla_certdata.txt\x00" as *u8) 183 if src < 0 { return 0 - 1 } 184 let dst: i64 = sys_openat_wr("/tmp/mozilla_certdata.txt\x00" as *u8, 0x1a4) 185 if dst < 0 { sys_close(src); return 0 - 2 } 186 let buf: *u8 = sys_mmap(65536) 187 var total: i64 = 0 188 var n: i64 = sys_read(src, buf, 65536) 189 while n > 0 { 190 sys_write(dst, buf, n) 191 total = total + n 192 n = sys_read(src, buf, 65536) 193 } 194 sys_close(src) 195 sys_close(dst) 196 return total 197} 198 199func main() -> i64 { 200 let names: *i64 = sys_mmap(8 * (BG_ROWS + 1)) as *i64 201 names[0] = "_arg7_minrepro\x00" as *u8 as i64 202 names[1] = "nx_tls13_kdf_test\x00" as *u8 as i64 203 names[2] = "nx_tls13_schedule_test\x00" as *u8 as i64 204 names[3] = "nx_jpeg_ascii_test\x00" as *u8 as i64 205 names[4] = "nx_browser_page_demo_test\x00" as *u8 as i64 206 names[5] = "nx_browser_own_site_live_test\x00" as *u8 as i64 207 names[6] = "nx_browser_render_own_test\x00" as *u8 as i64 208 names[7] = "nx_tls13_recv_hs_probe_test\x00" as *u8 as i64 209 names[8] = "nx_p256_keyshare_test\x00" as *u8 as i64 210 names[9] = "nx_tls13_ch_compat_test\x00" as *u8 as i64 211 names[10] = "_derefcast_minrepro\x00" as *u8 as i64 212 names[11] = "nx_tls13_p256_loopback_test\x00" as *u8 as i64 213 214 let envp: *i64 = sys_mmap(8 * 4) as *i64 215 envp[0] = "PATH=/usr/bin:/bin\x00" as *u8 as i64 216 envp[1] = 0 217 let devnull: i64 = sys_openat_wr("/dev/null\x00" as *u8, 0x1a4) 218 let logfd: i64 = sys_openat_append("knowledge/status/browser_gate.log\x00" as *u8, 0x1a4) 219 220 if logfd > 0 { 221 bg_fputs(logfd, "BROWSER-GATE epoch=\x00" as *u8) 222 bg_fputn(logfd, sys_now_realtime_sec()) 223 bg_fputs(logfd, " run-start\n\x00" as *u8) 224 } 225 226 let staged: i64 = bg_stage_certdata() 227 bg_fputs(1, "BROWSER-GATE stage=certdata bytes=\x00" as *u8) 228 bg_putn(staged) 229 bg_fputs(1, "\n\x00" as *u8) 230 if logfd > 0 { 231 bg_fputs(logfd, "BROWSER-GATE stage=certdata bytes=\x00" as *u8) 232 bg_fputn(logfd, staged) 233 bg_fputs(logfd, "\n\x00" as *u8) 234 } 235 236 var passed: i64 = 0 237 var ri: i64 = 0 238 while ri < BG_ROWS { 239 let name: *u8 = names[ri] as *u8 240 let brc: i64 = bg_build(name, envp, devnull) 241 var exit_code: i64 = 0 - 1 242 var sig: i64 = 0 - 1 243 var pass: i64 = 0 244 if brc == 0 { 245 let elf: *u8 = "/tmp/bg_row.elf\x00" 246 let a: *i64 = sys_mmap(8 * 3) as *i64 247 a[0] = elf as i64; a[1] = 0 248 let raw: i64 = bg_run(elf, a, envp, devnull, devnull) 249 exit_code = (raw >> 8) & 0xff 250 sig = raw & 0x7f 251 if exit_code == 0 { if sig == 0 { pass = 1 } } 252 } 253 bg_report(logfd, name, brc, exit_code, sig, pass) 254 passed = passed + pass 255 ri = ri + 1 256 } 257 258 let permil: i64 = (passed * 1000) / BG_ROWS 259 var fdi: i64 = 0 260 while fdi < 2 { 261 var fd: i64 = 1 262 if fdi == 1 { fd = logfd } 263 if fd > 0 { 264 bg_fputs(fd, "BROWSER-GATE rows=\x00" as *u8) 265 bg_fputn(fd, BG_ROWS) 266 bg_fputs(fd, " passed=\x00" as *u8) 267 bg_fputn(fd, passed) 268 bg_fputs(fd, " permil=\x00" as *u8) 269 bg_fputn(fd, permil) 270 if passed == BG_ROWS { bg_fputs(fd, " verdict=GREEN\n\x00" as *u8) } 271 if passed != BG_ROWS { bg_fputs(fd, " verdict=RED\n\x00" as *u8) } 272 } 273 fdi = fdi + 1 274 } 275 if logfd > 0 { sys_close(logfd) } 276 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 277 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 278 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 279 let ctr__dry: *i64 = gv_ctr() 280 ctr__dry[0] = passed 281 ctr__dry[1] = BG_ROWS 282 let rc__dry: i64 = gv_verdict("BROWSER-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 283 sys_exit(rc__dry) 284 return rc__dry 285}