code wiki / (root) / nx_browser_gate.nx

nx_browser_gate.nx source

↩ module page · 694 lines · 32435 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 builds it through THE SOVEREIGN 6// BUILD LANE (_offc/nx_sov_build_run.elf <mod> --build-only -- nx_cc -> 7// nxasm_x86, no gcc, no binutils), runs the artifact that lane names, 8// and judges via the RAW wait4 status (the sovereign exit-judging law -- 9// never $? through a shell). 10// 11// Rows (the browser claim set, 2026-06-10): 12// arg7-tailcall compiler regression gate: >6-arg tail-call drop 13// (the defect that zeroed every TLS Derive-Secret) 14// tls-kdf RFC 8448 Derive-Secret KATs 15// tls-schedule TLS 1.3 key-schedule KATs 16// jpeg-ascii deterministic synthetic-JPEG decode + raster 17// page-demo live HTTP fetch + html_to_text (example.com:80) 18// own-site-live LIVE sovereign HTTPS fetch of nishifamily.com 19// (TLS 1.3 + real Mozilla CA chain validation) 20// render-own paints the FETCHED page's text -> framebuffer 21// (consumes own-site-live's /tmp/nishi_own.html) 22// recv-hs-probe B1 rung: full encrypted-handshake walk vs 23// example.com (per-record/per-message markers, 24// cert-pipeline verdict + chain sig-alg census); 25// exit 0 = handshake to WAIT_CLIENT_FIN 26// p256-keyshare B4 rung: P-256 ECDH (RFC 5903 KAT both 27// directions, boundary rejects) + dual key_share 28// wire format (x25519 + secp256r1 in one CH) 29// derefcast compiler regression gate: `*p as T` precedence 30// (pre-fix: cast bound inside the deref -> byte- 31// load of the pointer cell -> SIGSEGV; fixed in 32// parse_unary 2026-06-10) 33// p256-loopback B4 server side: OUR server completes a P-256-only 34// client (no HRR), both roles derive byte-identical 35// traffic secrets, off-curve share rejected (the 36// nishifamily P-256 gap, healed + loopback-proven) 37// ch-compat B2 rung, two live legs: httpbin.org census 38// (TLS-1.2-only signature classified -- the CH 39// was never the defect; auto-escalates to a full 40// handshake if they enable 1.3) + github.com 41// P-256-only CH walked to verified server 42// Finished (GR=23: live proof of the B4 path) 43// browser-shot (2026-08-27) THE SHIPPED BROWSER ITSELF: forks the 44// nx_browser artifact's headless `shot` verb over a 45// fixture assembled at run time, png-out "-" (full 46// layout, PNG deliberately not written). Subject is 47// SUBSTITUTABLE: argv[1] names the artifact to judge 48// (the ship loop passes the staged build, nx_gate_bite 49// `subject nx_browser` passes the mutant); argless, the 50// PROMOTED ./nx_browser.elf (or ../) -- what is served. 51// Rows 0..11 prove the LIBRARIES the browser is built 52// from; none of them executes nx_browser.elf, so without 53// this row a ship could pass with a browser that cannot 54// lay out a page, and a subject-mode bite reached nothing. 55// 56// Verdict lines stream to stdout AND append to the durable log 57// knowledge/status/browser_gate.log (Archivist durability rule -- 58// /tmp dies on reboot, knowledge/ does not). 59// 60// ---- THE SOVEREIGN BUILD LANE (2026-08-27) ------------------------------- 61// Until this day bg_build compiled each row with the laptop's native x86 62// compiler and then shelled the .s through /usr/bin/as and /usr/bin/ld. 63// MEASURED on the NAS: that compiler does not exist here at all 64// (nx_catalog: ABSENT), and the moment the sovereign compiler was 65// substituted every row moved build=1 -> build=2 -- the NEXT stage died, 66// because the sovereign host deliberately ships NO binutils ("SOVEREIGN 67// (nx_cc->nxasm_x86, no gcc)" is what this estate's own builder prints). 68// So for its entire recent history this gate published "passed 0/12 69// verdict=RED" about a browser nothing had examined. A GATE THAT CANNOT 70// BUILD ITS SUBJECT MUST ABSTAIN, NOT CONVICT -- and the remedy is not a 71// third compiler path, it is to build the rows THE WAY EVERYTHING ELSE ON 72// THIS HOST IS BUILT: fork the estate's one builder. That buys, for free, 73// its content-addressed build cache (a repeat of this gate is a cache HIT 74// per row, so the roster cost is the rows' own runtime), its per-target 75// flock, its build deadline, its tree-canon admission and its load 76// governor. A refusal by that governor is a fact about the BOX, not the 77// browser, so it is recorded as a PRECONDITION (gv_need -> SKIP), never 78// as a row FAIL. Only "the row's source does not build" and "the row ran 79// and exited nonzero" are failures, because only those are evidence about 80// the claim set. 81// 82// Exit: gv_verdict -- 0 GREEN (every declared row built and exited 0), 83// 1 RED (a row failed), 3 SKIP (a precondition kept some row from running 84// and nothing that ran failed). ORCHESTRATION is pure NishiLang 85// fork/dup3/execve/wait4 -- NO shell, NO .sh. 86// 87// license_tier: ORIGINAL 88 89import "nx_syscalls.nx" 90import "nx_gate_verdict.nx" 91 92const BG_BUILD_ROWS: i64 = 12 // rows built from runtime/<mod>.nx through the sovereign lane 93const BG_SHOT_ROW: i64 = 12 // index of the browser-shot row (the shipped artifact itself) 94const BG_ROWS: i64 = 13 // every declared row: BG_BUILD_ROWS + the shot row 95const BG_SHOT_ARGV_SLOTS: i64 = 5 // artifact, shot, fixture, png-out, NUL 96const BG_PATH_CAP: i64 = 512 // one resolved path 97const BG_LINE_CAP: i64 = 512 // the builder's last output line, carried onto the row that failed to build 98const BG_NUM_CAP: i64 = 28 // decimal scratch 99const BG_ARGV_SLOTS: i64 = 4 // builder argv: elf, module, --build-only, NUL 100const BG_MODE_644: i64 = 420 101const BG_COPY_CHUNK: i64 = 65536 102// wait4 status decoding: exit code in bits 8..15, terminating signal in bits 0..6 103const BG_EXIT_SHIFT: i64 = 8 104const BG_EXIT_MASK: i64 = 255 105const BG_SIG_MASK: i64 = 127 106const BG_EXEC_FAIL: i64 = 127 // what bg_run's child exits with when execve itself fails 107const BG_SPACE: i64 = 32 108const BG_TAB: i64 = 9 109const BG_LF: i64 = 10 110const BG_CR: i64 = 13 111 112// bg_build outcomes. The first four are EVIDENCE about the row and count as a row that RAN; 113// the rest mean the row was NOT RUN and name why, so gv_need can carry the reason to the verdict. 114const BG_B_OK: i64 = 0 115const BG_B_COMPILE_FAIL: i64 = 1 // the row's source does not compile/assemble -- a row FAIL 116const BG_B_SRC_NOT_FOUND: i64 = 4 // runtime/<mod>.nx absent under both roots -- a row FAIL (the claim set names a source that is gone) 117const BG_B_NO_ARTIFACT: i64 = 5 // the builder exited 0 and named no artifact -- fail loud, never run a fossil 118const BG_B_BUILDER_OTHER: i64 = 10 // any other builder exit (usage etc.) -- a row FAIL with the builder's own last line as the reason 119const BG_B_ADMIT_REFUSED: i64 = 6 // nx_build_admit said no: a fact about the BOX -> NOT RUN 120const BG_B_CANON_REFUSED: i64 = 7 // tree-canon divergence: compiling would prove a FORKED copy -> NOT RUN 121const BG_B_BUILD_TIMEOUT: i64 = 8 // the builder's own deadline fired -> NOT RUN 122const BG_B_BUILDER_EXEC: i64 = 9 // the builder could not be exec'd or died by signal -> NOT RUN 123 124// The builder's exit codes, mirrored from nx_sov_build_run.nx (SBR_USAGE .. SBR_BUILD_TIMEOUT). 125// That file carries a main() and cannot be imported; the names are kept identical to its SBR_* consts 126// so a grep for either spelling finds both, and its comment block is the source of truth. 127const BG_SBR_USAGE: i64 = 2 128const BG_SBR_COMPILE_FAIL: i64 = 3 129const BG_SBR_ASM_FAIL: i64 = 4 130const BG_SBR_ADMIT_REFUSED: i64 = 6 131const BG_SBR_CANON_REFUSED: i64 = 7 132const BG_SBR_BUILD_TIMEOUT: i64 = 8 133 134func bg_puts(s: *u8) -> i64 { 135 var n: i64 = 0 136 while s[n] != (0 as u8) { n = n + 1 } 137 sys_write(1, s, n) 138 return 0 139} 140 141func bg_fputs(fd: i64, s: *u8) -> i64 { 142 var n: i64 = 0 143 while s[n] != (0 as u8) { n = n + 1 } 144 sys_write(fd, s, n) 145 return 0 146} 147 148func bg_fputn(fd: i64, v: i64) -> i64 { 149 let bb: *u8 = sys_mmap(BG_NUM_CAP) 150 var m: i64 = v 151 if m < 0 { m = 0 - m; sys_write(fd, "-" as *u8, 1) } 152 let t: *u8 = sys_mmap(BG_NUM_CAP) 153 var k: i64 = 0 154 if m == 0 { t[0] = 48 as u8; k = 1 } 155 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 156 var i: i64 = 0 157 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 158 sys_write(fd, bb, k) 159 return 0 160} 161 162func bg_putn(v: i64) -> i64 { bg_fputn(1, v); return 0 } 163 164func bg_cat(dst: *u8, off: i64, s: *u8) -> i64 { 165 var i: i64 = 0 166 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 } 167 return off + i 168} 169 170// fork + redirects + execve; parent waits; returns RAW wait status. 171func bg_run(path: *u8, argv: *i64, envp: *i64, redir_out: i64, redir_err: i64) -> i64 { 172 let pid: i64 = sys_fork() 173 if pid == 0 { 174 if redir_out >= 0 { sys_dup3(redir_out, 1, 0) } 175 if redir_err >= 0 { sys_dup3(redir_err, 2, 0) } 176 sys_execve(path, argv, envp) 177 sys_exit(BG_EXEC_FAIL) 178 } 179 let st: *i64 = sys_mmap(16) as *i64 180 sys_wait4(pid, st, 0) 181 return st[0] 182} 183 184func bg_exists(path: *u8) -> i64 { 185 let fd: i64 = sys_openat_rd(path) 186 if fd < 0 { return 0 } 187 sys_close(fd) 188 return 1 189} 190 191// ---- HOST-RESOLVED ROOTS -------------------------------------------------------------------- 192// MEASURED 2026-08-27: _offc/, data/ and knowledge/ resolve at the SERVING root (this gate's own log 193// lands there), while runtime/ exists ONLY under buildroot/ -- and /api/gate_run launches a gate with 194// CWD=buildroot while nx_organ_ship and the roster launch it from the serving root. No single CWD 195// satisfies the path set, so every root-relative path is RESOLVED BY PROBING both vantages. Fixing one 196// vantage would be half a fix, and the missing half is the one the other launcher exercises. 197 198// The estate's builder, probed at the runners' twin (_offc/) first, then the serving-root copy, at both 199// vantages. 0 means the caller must SKIP -- a gate that cannot build its rows has no evidence to give. 200func bg_sov_resolve() -> *u8 { 201 let p0: *u8 = "_offc/nx_sov_build_run.elf\x00" 202 if bg_exists(p0) == 1 { return p0 } 203 let p1: *u8 = "../_offc/nx_sov_build_run.elf\x00" 204 if bg_exists(p1) == 1 { return p1 } 205 let p2: *u8 = "nx_sov_build_run.elf\x00" 206 if bg_exists(p2) == 1 { return p2 } 207 let p3: *u8 = "../nx_sov_build_run.elf\x00" 208 if bg_exists(p3) == 1 { return p3 } 209 return 0 as *u8 210} 211 212// Resolve <root>/runtime/<mod>.nx against the roots this host has. 1 = found. 213func bg_src_resolve(mod: *u8, out: *u8) -> i64 { 214 var o: i64 = 0 215 o = bg_cat(out, o, "buildroot/runtime/\x00" as *u8) 216 o = bg_cat(out, o, mod) 217 o = bg_cat(out, o, ".nx\x00" as *u8) 218 out[o] = 0 as u8 219 if bg_exists(out) == 1 { return 1 } 220 o = 0 221 o = bg_cat(out, o, "runtime/\x00" as *u8) 222 o = bg_cat(out, o, mod) 223 o = bg_cat(out, o, ".nx\x00" as *u8) 224 out[o] = 0 as u8 225 if bg_exists(out) == 1 { return 1 } 226 return 0 227} 228 229// Where the builder leaves the artifact. nx_sov_build_run anchors ITS OWN CWD to buildroot/ whatever 230// the caller's is and writes _build/<mod>.sov.elf there, so from the serving root that is 231// buildroot/_build/<mod>.sov.elf and from buildroot/ it is _build/<mod>.sov.elf. Write the path for 232// candidate `which` (0 or 1) into out. 233func bg_artifact_path(mod: *u8, which: i64, out: *u8) -> i64 { 234 var o: i64 = 0 235 if which == 0 { o = bg_cat(out, o, "buildroot/_build/\x00" as *u8) } 236 if which == 1 { o = bg_cat(out, o, "_build/\x00" as *u8) } 237 o = bg_cat(out, o, mod) 238 o = bg_cat(out, o, ".sov.elf\x00" as *u8) 239 out[o] = 0 as u8 240 return o 241} 242 243func bg_artifact_resolve(mod: *u8, out: *u8) -> i64 { 244 bg_artifact_path(mod, 0, out) 245 if bg_exists(out) == 1 { return 1 } 246 bg_artifact_path(mod, 1, out) 247 if bg_exists(out) == 1 { return 1 } 248 return 0 249} 250 251// A stale artifact from an earlier build must never be what a row RUNS: the builder unlinks its own 252// before compiling, and this gate unlinks both candidates too, so the invariant is local to this file 253// -- THE ARTIFACT EXISTS IFF THIS BUILD SUCCEEDED -- and does not depend on which builder ran. 254func bg_artifact_unlink(mod: *u8) -> i64 { 255 let p: *u8 = sys_mmap(BG_PATH_CAP) 256 bg_artifact_path(mod, 0, p) 257 sys_unlinkat(p) 258 bg_artifact_path(mod, 1, p) 259 sys_unlinkat(p) 260 return 0 261} 262 263// Last non-empty line of a file, tabs/CRs spaced, NUL-terminated into out (cap bytes). Returns its 264// length, 0 when the file is absent or empty. THE REASON TRAVELS WITH THE COUNT: a row that failed to 265// build carries the builder's own last line, so a reader does not have to re-run the build to learn why. 266func bg_last_line(path: *u8, out: *u8, cap: i64) -> i64 { 267 out[0] = 0 as u8 268 let lenp: *i64 = sys_mmap(16) as *i64 269 let b: *u8 = sys_read_file(path, lenp) 270 if (b as i64) == 0 { return 0 } 271 let n: i64 = lenp[0] 272 if n <= 0 { return 0 } 273 var e: i64 = n 274 var fend: i64 = 0 275 while fend == 0 { 276 if e <= 0 { fend = 1 } else { 277 if b[e - 1] == (BG_LF as u8) { e = e - 1 } else { 278 if b[e - 1] == (BG_CR as u8) { e = e - 1 } else { fend = 1 } 279 } 280 } 281 } 282 var s: i64 = e 283 var fstart: i64 = 0 284 while fstart == 0 { 285 if s <= 0 { fstart = 1 } else { 286 if b[s - 1] == (BG_LF as u8) { fstart = 1 } else { s = s - 1 } 287 } 288 } 289 var k: i64 = 0 290 while s < e { 291 if k < cap - 1 { 292 var c: u8 = b[s] 293 if c == (BG_TAB as u8) { c = BG_SPACE as u8 } 294 if c == (BG_CR as u8) { c = BG_SPACE as u8 } 295 out[k] = c 296 k = k + 1 297 } 298 s = s + 1 299 } 300 out[k] = 0 as u8 301 sys_free_file(b, n) 302 return k 303} 304 305// Build <mod> through the sovereign lane. On BG_B_OK `art` holds the artifact path to run. 306// The builder's stdout+stderr go to `logpath` (truncated per row) so its last line can be carried. 307func bg_build(mod: *u8, sov: *u8, envp: *i64, logpath: *u8, art: *u8) -> i64 { 308 let src: *u8 = sys_mmap(BG_PATH_CAP) 309 if bg_src_resolve(mod, src) == 0 { return BG_B_SRC_NOT_FOUND } 310 bg_artifact_unlink(mod) 311 let lfd: i64 = sys_openat_wr(logpath, BG_MODE_644) 312 let a: *i64 = sys_mmap(8 * BG_ARGV_SLOTS) as *i64 313 a[0] = sov as i64 314 a[1] = mod as i64 315 a[2] = "--build-only\x00" as *u8 as i64 316 a[3] = 0 317 let raw: i64 = bg_run(sov, a, envp, lfd, lfd) 318 if lfd >= 0 { sys_close(lfd) } 319 let ec: i64 = (raw >> BG_EXIT_SHIFT) & BG_EXIT_MASK 320 let sg: i64 = raw & BG_SIG_MASK 321 if sg != 0 { return BG_B_BUILDER_EXEC } 322 if ec == BG_EXEC_FAIL { return BG_B_BUILDER_EXEC } 323 if ec == BG_SBR_ADMIT_REFUSED { return BG_B_ADMIT_REFUSED } 324 if ec == BG_SBR_CANON_REFUSED { return BG_B_CANON_REFUSED } 325 if ec == BG_SBR_BUILD_TIMEOUT { return BG_B_BUILD_TIMEOUT } 326 if ec == BG_SBR_COMPILE_FAIL { return BG_B_COMPILE_FAIL } 327 if ec == BG_SBR_ASM_FAIL { return BG_B_COMPILE_FAIL } 328 if ec != 0 { return BG_B_BUILDER_OTHER } 329 if bg_artifact_resolve(mod, art) == 0 { return BG_B_NO_ARTIFACT } 330 return BG_B_OK 331} 332 333// Emit one row verdict to stdout + durable log. Fields 1..5 are the shape every reader of 334// browser_gate.log already indexes; verdict gained the word NOT-RUN and `reason=` is ADDITIVE (only 335// printed when non-empty), rule 19. 336func bg_report(logfd: i64, name: *u8, build_rc: i64, exit_code: i64, sig: i64, word: *u8, reason: *u8) -> i64 { 337 var fdi: i64 = 0 338 while fdi < 2 { 339 var fd: i64 = 1 340 if fdi == 1 { fd = logfd } 341 if fd > 0 { 342 bg_fputs(fd, "BROWSER-GATE row=\x00" as *u8) 343 bg_fputs(fd, name) 344 bg_fputs(fd, " build=\x00" as *u8) 345 bg_fputn(fd, build_rc) 346 bg_fputs(fd, " exit=\x00" as *u8) 347 bg_fputn(fd, exit_code) 348 bg_fputs(fd, " sig=\x00" as *u8) 349 bg_fputn(fd, sig) 350 bg_fputs(fd, " verdict=\x00" as *u8) 351 bg_fputs(fd, word) 352 if reason[0] != (0 as u8) { 353 bg_fputs(fd, " reason=\x00" as *u8) 354 bg_fputs(fd, reason) 355 } 356 bg_fputs(fd, "\n\x00" as *u8) 357 } 358 fdi = fdi + 1 359 } 360 return 0 361} 362 363// Stage the real Mozilla CA bundle from the DURABLE estate copy into /tmp. 364// tmpfs dies on every reboot (proven 2026-06-10: crash wiped it and turned 365// own-site-live + render-own RED); the estate copy does not -- Archivist rule. 366// 367// THE BUNDLE LIVES AT data/mozilla_certdata.txt, RELATIVE TO THE SERVING ROOT (2026-08-27). That is the 368// path forty-odd organs in this estate open it at (nx_browse, nx_crawl_web, nx_page_verify, the tls12 369// gates, nx_cleanview with the absolute fallback spelled out). This gate asked for 370// knowledge/library/mozilla_certdata.txt, which is ABSENT-PROVEN on the NAS -- so its live-TLS rows 371// could never have validated a chain here, and the stage line printed bytes=-1 on every run. Probed 372// at both vantages (see the roots note above); the chosen source path is announced. 373// 374// ALWAYS restage (idempotent, rule 10): the old "size>1MB -> skip" check 375// refused to refresh a STALE-but-large /tmp bundle, so once a rotted bundle 376// sat in /tmp the live-TLS rows rotted with it -- this was the entire 377// "TLS-FIN bedrock regression" (2026-06-13: stale /tmp bundle drove 378// recv_hs_probe exit=44 + ch_compat exit=144 while example.com/github.com 379// validated fine against the fresh durable bundle). /tmp now ends byte-equal 380// to the estate copy every run; the reported byte count also makes freshness 381// self-evident in the log instead of a silent "bytes=0". 382// Returns bytes staged, negative on missing/unwritable target. `used` receives the source path. 383func bg_stage_certdata(used: *u8) -> i64 { 384 var srcpath: *u8 = "data/mozilla_certdata.txt\x00" as *u8 385 var src: i64 = sys_openat_rd(srcpath) 386 if src < 0 { 387 srcpath = "../data/mozilla_certdata.txt\x00" as *u8 388 src = sys_openat_rd(srcpath) 389 } 390 var uo: i64 = bg_cat(used, 0, srcpath) 391 used[uo] = 0 as u8 392 if src < 0 { return 0 - 1 } 393 let dst: i64 = sys_openat_wr("/tmp/mozilla_certdata.txt\x00" as *u8, BG_MODE_644) 394 if dst < 0 { sys_close(src); return 0 - 2 } 395 let buf: *u8 = sys_mmap(BG_COPY_CHUNK) 396 var total: i64 = 0 397 var n: i64 = sys_read(src, buf, BG_COPY_CHUNK) 398 while n > 0 { 399 sys_write(dst, buf, n) 400 total = total + n 401 n = sys_read(src, buf, BG_COPY_CHUNK) 402 } 403 sys_close(src) 404 sys_close(dst) 405 return total 406} 407 408// THE BROWSER ARTIFACT TO JUDGE. argv[1] when given (the caller says which build); otherwise the 409// PROMOTED binary, probed at both vantages. Writes the path it settled on into out; 1 = it exists. 410func bg_subject_resolve(argc: i64, argv: *i64, out: *u8) -> i64 { 411 var o: i64 = 0 412 if argc >= 2 { 413 o = bg_cat(out, 0, argv[1] as *u8) 414 out[o] = 0 as u8 415 return bg_exists(out) 416 } 417 o = bg_cat(out, 0, "nx_browser.elf\x00" as *u8) 418 out[o] = 0 as u8 419 if bg_exists(out) == 1 { return 1 } 420 o = bg_cat(out, 0, "../nx_browser.elf\x00" as *u8) 421 out[o] = 0 as u8 422 if bg_exists(out) == 1 { return 1 } 423 return 0 424} 425 426// The shot fixture, ASSEMBLED AT RUN TIME (a detector that scans source finds its own fixtures): 427// a heading, a paragraph with an inline link, and a two-cell table -- block, inline and table layout 428// in one page, so a browser that has lost any of the three cannot lay it out into real boxes. 429// Returns bytes written, negative when /tmp is unwritable. 430func bg_write_shot_fixture(path: *u8) -> i64 { 431 let fd: i64 = sys_openat_wr(path, BG_MODE_644) 432 if fd < 0 { return 0 - 1 } 433 let body: *u8 = "<!doctype html><html><head><title>bg shot</title><style>body{font-family:sans-serif} td{padding:4px}</style></head><body><h1>Browser gate shot fixture</h1><p>One paragraph with an <a href=/x>inline link</a> and enough words to wrap at a narrow viewport width when laid out.</p><table><tr><td>cell one</td><td>cell two</td></tr></table></body></html>\n\x00" 434 var n: i64 = 0 435 while body[n] != (0 as u8) { n = n + 1 } 436 let w: i64 = sys_write(fd, body, n) 437 sys_close(fd) 438 return w 439} 440 441// The durable log, at whichever vantage holds knowledge/status/. 442func bg_open_log() -> i64 { 443 var fd: i64 = sys_openat_append("knowledge/status/browser_gate.log\x00" as *u8, BG_MODE_644) 444 if fd < 0 { fd = sys_openat_append("../knowledge/status/browser_gate.log\x00" as *u8, BG_MODE_644) } 445 return fd 446} 447 448func main(argc: i64, argv: *i64) -> i64 { 449 let names: *i64 = sys_mmap(8 * (BG_ROWS + 1)) as *i64 450 names[0] = "_arg7_minrepro\x00" as *u8 as i64 451 names[1] = "nx_tls13_kdf_test\x00" as *u8 as i64 452 names[2] = "nx_tls13_schedule_test\x00" as *u8 as i64 453 names[3] = "nx_jpeg_ascii_test\x00" as *u8 as i64 454 names[4] = "nx_browser_page_demo_test\x00" as *u8 as i64 455 names[5] = "nx_browser_own_site_live_test\x00" as *u8 as i64 456 names[6] = "nx_browser_render_own_test\x00" as *u8 as i64 457 names[7] = "nx_tls13_recv_hs_probe_test\x00" as *u8 as i64 458 names[8] = "nx_p256_keyshare_test\x00" as *u8 as i64 459 names[9] = "nx_tls13_ch_compat_test\x00" as *u8 as i64 460 names[10] = "_derefcast_minrepro\x00" as *u8 as i64 461 names[11] = "nx_tls13_p256_loopback_test\x00" as *u8 as i64 462 names[12] = "nx_browser:shot\x00" as *u8 as i64 463 // Which rows need the staged CA bundle: own-site-live, recv-hs-probe and ch-compat open 464 // /tmp/mozilla_certdata.txt directly (measured: 2 references each in their source), and render-own 465 // consumes the /tmp/nishi_own.html that own-site-live writes, so it needs it transitively. 466 // A row that needs an absent fixture is NOT RUN with the fixture named, never run-and-convicted. 467 let needs_ca: *i64 = sys_mmap(8 * (BG_ROWS + 1)) as *i64 468 var zi: i64 = 0 469 while zi < BG_ROWS { needs_ca[zi] = 0; zi = zi + 1 } 470 needs_ca[5] = 1 471 needs_ca[6] = 1 472 needs_ca[7] = 1 473 needs_ca[9] = 1 474 475 let envp: *i64 = sys_mmap(8 * 4) as *i64 476 envp[0] = "PATH=/usr/bin:/bin\x00" as *u8 as i64 477 envp[1] = 0 478 let devnull: i64 = sys_openat_wr("/dev/null\x00" as *u8, BG_MODE_644) 479 let logfd: i64 = bg_open_log() 480 let buildlog: *u8 = "/tmp/bg_row_build.log\x00" 481 482 if logfd > 0 { 483 bg_fputs(logfd, "BROWSER-GATE epoch=\x00" as *u8) 484 bg_fputn(logfd, sys_now_realtime_sec()) 485 bg_fputs(logfd, " run-start\n\x00" as *u8) 486 } 487 488 let cdsrc: *u8 = sys_mmap(BG_PATH_CAP) 489 let staged: i64 = bg_stage_certdata(cdsrc) 490 var fdi: i64 = 0 491 while fdi < 2 { 492 var fd: i64 = 1 493 if fdi == 1 { fd = logfd } 494 if fd > 0 { 495 bg_fputs(fd, "BROWSER-GATE stage=certdata src=\x00" as *u8) 496 bg_fputs(fd, cdsrc) 497 bg_fputs(fd, " bytes=\x00" as *u8) 498 bg_fputn(fd, staged) 499 bg_fputs(fd, "\n\x00" as *u8) 500 } 501 fdi = fdi + 1 502 } 503 504 // ---- PRECONDITIONS BEFORE ROWS --------------------------------------------------------------- 505 // The counters are created HERE rather than at the end, so gv_need can record a missing 506 // precondition and gv_verdict can actually REACH its SKIP branch. The base class's ordering is 507 // untouched and this can only ever un-bless: a real row failure still escalates SKIP -> RED, so an 508 // absent precondition can never amnesty a defect. (The D001 migration had left a fresh gv_ctr() at 509 // the END, which silently discarded ctr[2] and sent a toolchain-less run back out as RED.) 510 let ctr: *i64 = gv_ctr() 511 let sov: *u8 = bg_sov_resolve() 512 var sov_ok: i64 = 0 513 if (sov as i64) != 0 { sov_ok = 1 } 514 gv_need("the sovereign builder nx_sov_build_run.elf (probed at _offc/ and ../_offc/, then the serving root and ../) -- without it no row can be built here" as *u8, sov_ok, ctr) 515 var cd_ok: i64 = 0 516 if staged > 0 { cd_ok = 1 } 517 gv_need("data/mozilla_certdata.txt (the estate's CA bundle, serving root or ../) -- own-site-live, render-own, recv-hs-probe and ch-compat validate a live chain against it" as *u8, cd_ok, ctr) 518 if sov_ok == 1 { 519 bg_puts("BROWSER-GATE builder=\x00" as *u8) 520 bg_puts(sov) 521 bg_puts("\n\x00" as *u8) 522 } 523 let subj: *u8 = sys_mmap(BG_PATH_CAP) 524 let subj_ok: i64 = bg_subject_resolve(argc, argv, subj) 525 gv_need("a browser artifact to judge (argv[1], else the promoted nx_browser.elf at ./ or ../) -- the browser-shot row forks it" as *u8, subj_ok, ctr) 526 bg_puts("BROWSER-GATE subject=\x00" as *u8) 527 bg_puts(subj) 528 bg_puts(" present=\x00" as *u8) 529 bg_putn(subj_ok) 530 bg_puts("\n\x00" as *u8) 531 let shot_fixture: *u8 = "/tmp/bg_shot_fixture.html\x00" 532 533 // WITH NO BUILDER THE BUILD ROWS ARE NOT RUN AT ALL: running them would fork a missing binary 534 // twelve times and report twelve rows about a browser nothing examined. The shot row needs no 535 // builder and still runs. 536 var nbuild: i64 = BG_BUILD_ROWS 537 if sov_ok == 0 { nbuild = 0 } 538 539 var run: i64 = 0 540 var passed: i64 = 0 541 var nr_ca: i64 = 0 542 var nr_admit: i64 = 0 543 var nr_canon: i64 = 0 544 var nr_timeout: i64 = 0 545 var nr_exec: i64 = 0 546 var nr_subject: i64 = 0 547 var nr_builder: i64 = 0 548 let art: *u8 = sys_mmap(BG_PATH_CAP) 549 let reason: *u8 = sys_mmap(BG_LINE_CAP) 550 var ri: i64 = 0 551 while ri < BG_ROWS { 552 let name: *u8 = names[ri] as *u8 553 reason[0] = 0 as u8 554 var exit_code: i64 = 0 - 1 555 var sig: i64 = 0 - 1 556 var brc: i64 = 0 - 1 557 var word: *u8 = "FAIL" as *u8 558 var attempted: i64 = 1 559 if ri < BG_BUILD_ROWS { if ri >= nbuild { 560 attempted = 0 561 nr_builder = nr_builder + 1 562 word = "NOT-RUN" as *u8 563 bg_cat(reason, 0, "no sovereign builder on this host\x00" as *u8) 564 } } 565 if needs_ca[ri] == 1 { if cd_ok == 0 { if attempted == 1 { 566 attempted = 0 567 nr_ca = nr_ca + 1 568 word = "NOT-RUN" as *u8 569 bg_cat(reason, 0, "needs the staged CA bundle\x00" as *u8) 570 } } } 571 if ri == BG_SHOT_ROW { if attempted == 1 { 572 attempted = 0 573 brc = BG_B_OK 574 if subj_ok == 0 { 575 nr_subject = nr_subject + 1 576 word = "NOT-RUN" as *u8 577 bg_cat(reason, 0, "no browser artifact to judge\x00" as *u8) 578 } else { 579 let fw: i64 = bg_write_shot_fixture(shot_fixture) 580 if fw <= 0 { 581 nr_exec = nr_exec + 1 582 word = "NOT-RUN" as *u8 583 bg_cat(reason, 0, "could not write the shot fixture under /tmp\x00" as *u8) 584 } else { 585 run = run + 1 586 let sa: *i64 = sys_mmap(8 * BG_SHOT_ARGV_SLOTS) as *i64 587 sa[0] = subj as i64 588 sa[1] = "shot\x00" as *u8 as i64 589 sa[2] = shot_fixture as i64 590 sa[3] = "-\x00" as *u8 as i64 591 sa[4] = 0 592 let sraw: i64 = bg_run(subj, sa, envp, devnull, devnull) 593 exit_code = (sraw >> BG_EXIT_SHIFT) & BG_EXIT_MASK 594 sig = sraw & BG_SIG_MASK 595 if exit_code == 0 { if sig == 0 { word = "PASS" as *u8; passed = passed + 1 } } 596 } 597 } 598 } } 599 if attempted == 1 { 600 brc = bg_build(name, sov, envp, buildlog, art) 601 if brc != BG_B_OK { bg_last_line(buildlog, reason, BG_LINE_CAP) } 602 var not_run: i64 = 0 603 if brc == BG_B_ADMIT_REFUSED { not_run = 1; nr_admit = nr_admit + 1 } 604 if brc == BG_B_CANON_REFUSED { not_run = 1; nr_canon = nr_canon + 1 } 605 if brc == BG_B_BUILD_TIMEOUT { not_run = 1; nr_timeout = nr_timeout + 1 } 606 if brc == BG_B_BUILDER_EXEC { not_run = 1; nr_exec = nr_exec + 1 } 607 if not_run == 1 { word = "NOT-RUN" as *u8 } 608 if not_run == 0 { 609 run = run + 1 610 if brc == BG_B_OK { 611 let a: *i64 = sys_mmap(8 * 3) as *i64 612 a[0] = art as i64 613 a[1] = 0 614 let raw: i64 = bg_run(art, a, envp, devnull, devnull) 615 exit_code = (raw >> BG_EXIT_SHIFT) & BG_EXIT_MASK 616 sig = raw & BG_SIG_MASK 617 if exit_code == 0 { if sig == 0 { word = "PASS" as *u8; passed = passed + 1 } } 618 } 619 } 620 } 621 bg_report(logfd, name, brc, exit_code, sig, word, reason) 622 ri = ri + 1 623 } 624 625 // Every NOT-RUN class is a precondition of its own, so the verdict line NAMES which one kept a row 626 // from running instead of folding them into one count with opposite remedies. 627 var admit_ok: i64 = 1 628 if nr_admit > 0 { admit_ok = 0 } 629 gv_need("build admission GRANTED for every row (nx_build_admit, consulted by the builder) -- a refusal is a fact about the box: re-run when it clears, never spin" as *u8, admit_ok, ctr) 630 var canon_ok: i64 = 1 631 if nr_canon > 0 { canon_ok = 0 } 632 gv_need("tree canon converged for every row -- the builder refuses to compile a forked copy" as *u8, canon_ok, ctr) 633 var tmo_ok: i64 = 1 634 if nr_timeout > 0 { tmo_ok = 0 } 635 gv_need("the builder finished every row inside its own build deadline" as *u8, tmo_ok, ctr) 636 var exec_ok: i64 = 1 637 if nr_exec > 0 { exec_ok = 0 } 638 gv_need("the builder exec'd cleanly for every row (no exec failure, no signal death)" as *u8, exec_ok, ctr) 639 640 // THE PARTITION IS PRINTED AND MUST SUM: run + not_run == of_declared, with not_run split by cause. 641 // permil is taken over the rows ACTUALLY RUN and is -1 when none were -- dividing by the DECLARED 642 // BG_ROWS is what once made a skipped run print "rows=12 passed=0 permil=0 verdict=RED", a fully 643 // populated failure report about twelve tests that never executed. The verdict word stays in the 644 // base class's vocabulary (GREEN/RED/SKIP) and is derived from the SAME conditions gv_verdict 645 // applies, so this line and the verdict line cannot disagree. 646 let not_run: i64 = BG_ROWS - run 647 var permil: i64 = 0 - 1 648 if run > 0 { permil = (passed * 1000) / run } 649 var word: *u8 = "GREEN" as *u8 650 if passed < run { word = "RED" as *u8 } else { if ctr[2] > 0 { word = "SKIP" as *u8 } } 651 fdi = 0 652 while fdi < 2 { 653 var fd: i64 = 1 654 if fdi == 1 { fd = logfd } 655 if fd > 0 { 656 bg_fputs(fd, "BROWSER-GATE rows=\x00" as *u8) 657 bg_fputn(fd, run) 658 bg_fputs(fd, " of_declared=\x00" as *u8) 659 bg_fputn(fd, BG_ROWS) 660 bg_fputs(fd, " passed=\x00" as *u8) 661 bg_fputn(fd, passed) 662 bg_fputs(fd, " not_run=\x00" as *u8) 663 bg_fputn(fd, not_run) 664 bg_fputs(fd, " (ca=\x00" as *u8) 665 bg_fputn(fd, nr_ca) 666 bg_fputs(fd, " admit=\x00" as *u8) 667 bg_fputn(fd, nr_admit) 668 bg_fputs(fd, " canon=\x00" as *u8) 669 bg_fputn(fd, nr_canon) 670 bg_fputs(fd, " timeout=\x00" as *u8) 671 bg_fputn(fd, nr_timeout) 672 bg_fputs(fd, " exec=\x00" as *u8) 673 bg_fputn(fd, nr_exec) 674 bg_fputs(fd, " subject=\x00" as *u8) 675 bg_fputn(fd, nr_subject) 676 bg_fputs(fd, " builder_absent=\x00" as *u8) 677 bg_fputn(fd, nr_builder) 678 bg_fputs(fd, "; run+not_run==of_declared) permil=\x00" as *u8) 679 bg_fputn(fd, permil) 680 bg_fputs(fd, " verdict=\x00" as *u8) 681 bg_fputs(fd, word) 682 bg_fputs(fd, "\n\x00" as *u8) 683 } 684 fdi = fdi + 1 685 } 686 if logfd > 0 { sys_close(logfd) } 687 // The ONE shared base class emits the verdict; the counters are the ones created BEFORE the rows, 688 // so every gv_need above survives to here and the third state is reachable. 689 ctr[0] = passed 690 ctr[1] = run 691 let rc__dry: i64 = gv_verdict("BROWSER-GATE" as *u8, ctr, "every declared row built through the sovereign lane and exited 0" as *u8) 692 sys_exit(rc__dry) 693 return rc__dry 694}