code wiki / (root) / nx_http_probe_gate.nx

nx_http_probe_gate.nx source

↩ module page · 428 lines · 21262 B

1// nx_http_probe_gate.nx -- THE REFEREE FOR nx_http_probe. Hermetic, in-process, no external service. 2// 3// WHAT IT HAS TO PROVE, AND WHY THE OBVIOUS GATE WOULD NOT PROVE IT. The organ under test replaces a 4// cron one-liner whose ONLY defect was that it failed SILENTLY: the row fired, the command did not run, 5// all output was discarded, and the capability-plane watch went stale at 10.9x its budget with nobody 6// able to name which link broke. A gate that only asks "does a healthy endpoint return 0" would pass a 7// probe that ALSO returns 0 for a dead one, and a gate that only reads exit codes would pass a probe 8// that stamps the heartbeat on a FAILING run -- which is the same blindness wearing a green badge. 9// So every failure fixture asserts TWO things: the NAMED exit code, and THE ABSENCE OF THE HEARTBEAT. 10// **** THE STAMP IS THE THING THE WATCHER BELIEVES. ASSERTING ITS ABSENCE IS THE TOOTH. **** 11// 12// THE POSITIVE CONTROL IS NOT DECORATION. A guard that refuses everything passes every negative test, 13// and four SSRF deny-tests once went green over a wholly broken guard for exactly that reason. T1-T4 14// are the input that MUST be accepted, so an always-fail probe cannot score. 15// 16// THE ABSENCE FIXTURES REUSE THE PATH THE POSITIVE CONTROL JUST WROTE. A fixture that asserts "no file 17// appeared at some path" is vacuous if nothing could ever have appeared there. T1/T2 prove this organ 18// writes THIS EXACT PATH; the failing runs then unlink it and prove it stays gone. 19// 20// FIXTURES ARE ASSEMBLED AT RUNTIME, NOT WRITTEN AS LITERALS. A source-scanning detector finds its own 21// fixture, and the estate has paid for that twice. The JSON marker is built from a quote byte, so the 22// needle and the body it lives in come from ONE code path and cannot drift apart. 23// 24// SCRATCH LIVES IN /tmp/nx_http_probe_gate/, NEVER the production tree: a gate that shares a fixture 25// with a production beat reports on the FIXTURE, not on the code (nx_gate_fixture_ratchet_gate). 26// Setup creates and clears; there is no teardown, because a teardown does not run when a run crashes. 27// 28// PORTS ARE PROVEN FREE BY BINDING THEM, NEVER ASSUMED. A probe port you did not verify free is not a 29// control, it is a second instance. If any port is taken the gate SKIPs -- "I could not look" is not 30// "it is broken". 31// 32// expect_exit: 0 license_tier: ORIGINAL No hw writes (Rule 26). 33import "nx_syscalls.nx" 34import "nx_clock.nx" 35import "nx_gate_verdict.nx" 36import "nx_http_probe_lib.nx" 37 38const HPG_PORT_OK: i64 = 19791 39const HPG_PORT_500: i64 = 19792 40const HPG_PORT_HANG: i64 = 19793 41const HPG_PORT_CLOSED: i64 = 19794 42const HPG_BACKLOG: i64 = 16 43const HPG_ADDR_BYTES: i64 = 16 44const HPG_BUF: i64 = 8192 45const HPG_DQUOTE: i64 = 34 46const HPG_DIR_MODE: i64 = 493 47// hp_run's last argument controls the PER-LEG TRACE lines only. It can never silence the verdict -- 48// the subject has no quiet mode by design -- so both settings still announce every outcome. 49const HPG_TRACE_OFF: i64 = 0 50const HPG_TRACE_ON: i64 = 1 51const HPG_NS_PER_MS: i64 = 1000000 52const HPG_BAD_CODE: i64 = 999 53// One second is enough for a loopback fixture and keeps the whole gate under a few seconds. The hang 54// fixture is the only one that spends it, and it spends it exactly once. 55const HPG_BUDGET_SEC: i64 = 1 56// The hang fixture must come back inside a WINDOW, not merely "eventually". The floor catches a probe 57// that never actually waited (a bail-out-instantly false pass); the ceiling is what fails a probe that 58// inherited the unbounded read this organ exists to replace -- that one would never return at all. 59const HPG_HANG_MIN_MS: i64 = 500 60const HPG_HANG_MAX_MS: i64 = 3000 61// The stamp epoch must land inside the run's own window. A hard-coded `ts=0`, or a fossil left by an 62// earlier run, fails this even though the file exists and parses. 63const HPG_EPOCH_SLACK: i64 = 120 64// fd numbers for the stderr-capture tooth. 2 is stderr by definition; the save slot is any fd this 65// process demonstrably does not use, and dup3 refuses oldfd==newfd so it can never alias stderr. 66const HPG_FD_STDERR: i64 = 2 67const HPG_FD_ERRSAVE: i64 = 200 68 69func hpg_cat(d: *u8, o: i64, s: *u8) -> i64 { 70 var i: i64 = 0 71 var p: i64 = o 72 while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } 73 return p 74} 75func hpg_catc(d: *u8, o: i64, c: i64) -> i64 { d[o] = c as u8; return o + 1 } 76 77// sockaddr_in for 127.0.0.1:<port>, via the SAME packer the subject uses. 78func hpg_sa(port: i64) -> *u8 { 79 let s: *u8 = sys_mmap(HPG_ADDR_BYTES) 80 nx_http_client_sockaddr_ipv4(s, 127, 0, 0, 1, port) 81 return s 82} 83 84// Bind+listen on a loopback port. Returns the listening fd, or -1 -- and -1 means THE PORT WAS TAKEN, 85// which is a precondition failure, not a verdict about the subject. 86func hpg_listen(port: i64) -> i64 { 87 let fd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 88 if fd < 0 { return 0 - 1 } 89 let opt: *i64 = sys_mmap(8) as *i64 90 opt[0] = 1 91 sys_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, opt as *u8, 4) 92 let sa: *u8 = hpg_sa(port) 93 if sys_bind(fd, sa, HPG_ADDR_BYTES) < 0 { sys_close(fd); return 0 - 1 } 94 if sys_listen(fd, HPG_BACKLOG) < 0 { sys_close(fd); return 0 - 1 } 95 return fd 96} 97 98// Fork a one-shot responder on an ALREADY-LISTENING fd. Binding in the PARENT before the fork removes 99// the classic fixture race entirely: the port is listening before the child exists, so the probe can 100// never arrive before the server is up. The child reads the request first so the peer never sees a RST. 101func hpg_respond_once(lfd: i64, resp: *u8, rlen: i64) -> i64 { 102 let pid: i64 = sys_fork() 103 if pid == 0 { 104 let cfd: i64 = sys_accept(lfd) 105 if cfd >= 0 { 106 let rq: *u8 = sys_mmap(HPG_BUF) 107 sys_read(cfd, rq, HPG_BUF) 108 sys_write(cfd, resp, rlen) 109 sys_close(cfd) 110 } 111 sys_exit(0) 112 } 113 return pid 114} 115 116func hpg_reap(pid: i64) -> i64 { 117 if pid <= 0 { return 0 } 118 let st: *i64 = sys_mmap(8) as *i64 119 sys_wait4(pid, st, 0) 120 sys_munmap(st as *u8, 8) 121 return 0 122} 123 124func hpg_exists(path: *u8) -> i64 { 125 let fd: i64 = sys_openat_rd(path) 126 if fd < 0 { return 0 } 127 sys_close(fd) 128 return 1 129} 130func hpg_slurp(path: *u8, dst: *u8, cap: i64) -> i64 { 131 let fd: i64 = sys_openat_rd(path) 132 if fd < 0 { return 0 - 1 } 133 let n: i64 = sys_read(fd, dst, cap - 1) 134 sys_close(fd) 135 if n < 0 { return 0 - 1 } 136 dst[n] = 0 as u8 137 return n 138} 139 140// THE MARKER AND THE BODY COME FROM ONE PLACE. dst gets "secure":<word> with real double quotes, 141// assembled from a byte so no literal in this source can be mistaken for the thing being detected. 142func hpg_marker(dst: *u8, word: *u8) -> i64 { 143 var o: i64 = 0 144 o = hpg_catc(dst, o, HPG_DQUOTE) 145 o = hpg_cat(dst, o, "secure" as *u8) 146 o = hpg_catc(dst, o, HPG_DQUOTE) 147 o = hpg_cat(dst, o, ":" as *u8) 148 o = hpg_cat(dst, o, word) 149 dst[o] = 0 as u8 150 return o 151} 152 153func hpg_response(dst: *u8, statusline: *u8, marker: *u8) -> i64 { 154 var o: i64 = 0 155 o = hpg_cat(dst, o, statusline) 156 o = hpg_cat(dst, o, "Content-Type: application/json\r\nConnection: close\r\n\r\n" as *u8) 157 o = hpg_cat(dst, o, "{" as *u8) 158 o = hpg_cat(dst, o, marker) 159 o = hpg_cat(dst, o, "}" as *u8) 160 dst[o] = 0 as u8 161 return o 162} 163 164func main(argc: i64, argv: *i64) -> i64 { 165 gv_head("nx_http_probe_gate -- the replacement for the silent curl cron row must be UNABLE to fail silently" as *u8) 166 let ctr: *i64 = gv_ctr() 167 168 // ---- SETUP. Idempotent: create the dir every run, clear the stamp before every use. ----------- 169 let dir: *u8 = "/tmp/nx_http_probe_gate" as *u8 170 sys_mkdir(dir, HPG_DIR_MODE) 171 let stamp: *u8 = "/tmp/nx_http_probe_gate/shared.stamp" as *u8 172 let badstamp: *u8 = "/tmp/nx_http_probe_gate/no-such-subdir/x.stamp" as *u8 173 sys_unlinkat(stamp) 174 175 // PORT_CLOSED is proven FREE by binding it and then closing it, so "connect refused" is a fact about 176 // the fixture and not a guess about what else might be running on this box. 177 let closed_probe: i64 = hpg_listen(HPG_PORT_CLOSED) 178 var closed_free: i64 = 0 179 if closed_probe >= 0 { closed_free = 1; sys_close(closed_probe) } 180 181 let l_ok: i64 = hpg_listen(HPG_PORT_OK) 182 let l_500: i64 = hpg_listen(HPG_PORT_500) 183 let l_hang: i64 = hpg_listen(HPG_PORT_HANG) 184 var ports_ok: i64 = 0 185 if l_ok >= 0 { if l_500 >= 0 { if l_hang >= 0 { if closed_free == 1 { ports_ok = 1 } } } } 186 gv_need("four loopback probe ports proven FREE by binding them (never assumed)" as *u8, ports_ok, ctr) 187 188 // Writability of the scratch dir is a precondition too: an unwritable /tmp makes every stamp tooth 189 // report on the environment rather than on the organ, in the same word. 190 var dirw: i64 = 0 191 let probe_fd: i64 = sys_openat_wr("/tmp/nx_http_probe_gate/.writecheck" as *u8, HP_MODE_0644) 192 if probe_fd >= 0 { dirw = 1; sys_close(probe_fd) } 193 gv_need("fixture dir /tmp/nx_http_probe_gate is writable" as *u8, dirw, ctr) 194 195 // STOP HERE IF WE CANNOT LOOK. Running the teeth against an unbuildable fixture would file 196 // environment failures as findings about the subject, in the same word -- the exact thing gv_need 197 // exists to prevent. gv_verdict with preconditions missing and nothing failed returns 3 = SKIP. 198 var can_run: i64 = 0 199 if ports_ok == 1 { if dirw == 1 { can_run = 1 } } 200 if can_run == 0 { 201 let rcskip: i64 = gv_verdict("HTTP-PROBE-GATE" as *u8, ctr, "unreachable" as *u8) 202 sys_exit(rcskip) 203 return rcskip 204 } 205 206 let need_true: *u8 = sys_mmap(HPG_BUF) 207 let need_false: *u8 = sys_mmap(HPG_BUF) 208 hpg_marker(need_true, "true" as *u8) 209 hpg_marker(need_false, "false" as *u8) 210 211 let r200: *u8 = sys_mmap(HPG_BUF) 212 let r500: *u8 = sys_mmap(HPG_BUF) 213 let n200: i64 = hpg_response(r200, "HTTP/1.1 200 OK\r\n" as *u8, need_true) 214 // THE 500 FIXTURE CARRIES THE *MATCHING* MARKER ON PURPOSE. If the status check were skipped, or 215 // ran after the pattern check, this run would come back clean -- so this tooth isolates the status 216 // conjunct instead of letting two signals pass as one. 217 let n500: i64 = hpg_response(r500, "HTTP/1.1 500 Internal Server Error\r\n" as *u8, need_true) 218 219 let sb: *u8 = sys_mmap(HPG_BUF) 220 221 // ================= T1-T4 POSITIVE CONTROL: the input that MUST be accepted ==================== 222 let t_before: i64 = sys_now_realtime_sec() 223 let p1: i64 = hpg_respond_once(l_ok, r200, n200) 224 let rc_ok: i64 = hp_run(HPG_PORT_OK, "/api/cap/status" as *u8, need_true, HPG_BUDGET_SEC, stamp, HPG_TRACE_ON) 225 hpg_reap(p1) 226 let t_after: i64 = sys_now_realtime_sec() 227 228 var c1: i64 = 0 229 if rc_ok == HP_EXIT_OK { c1 = 1 } 230 gv_check("pos-control-healthy-2xx-endpoint-with-the-marker-exits-0" as *u8, c1, ctr) 231 232 let stamped: i64 = hpg_exists(stamp) 233 gv_check("pos-control-a-clean-run-WRITES-the-heartbeat" as *u8, stamped, ctr) 234 235 // THE MARKER IS BOUND ONCE AND ITS LENGTH IS DERIVED. A hand-counted 3 beside "ts=" is a second copy 236 // of that literal's shape, and the two drift silently: change the marker, forget the number, and the 237 // parser reads the wrong window while still compiling and still appearing to work. 238 let sn: i64 = hpg_slurp(stamp, sb, HPG_BUF) 239 let tsmark: *u8 = "ts=" as *u8 240 let tsl: i64 = hp_strlen(tsmark) 241 var c3: i64 = 0 242 if sn > tsl { 243 c3 = 1 244 var m: i64 = 0 245 while m < tsl { if sb[m] != tsmark[m] { c3 = 0 } m = m + 1 } 246 } 247 gv_check("heartbeat-marker-is-the-one-nx_cron_watch-actually-parses" as *u8, c3, ctr) 248 249 var stamped_ts: i64 = 0 - 1 250 if sn > tsl { stamped_ts = hp_atoi(sb, tsl, sn - tsl) } 251 var c4: i64 = 0 252 if stamped_ts >= t_before - HPG_EPOCH_SLACK { 253 if stamped_ts <= t_after + HPG_EPOCH_SLACK { c4 = 1 } 254 } 255 gv_puts(" stamp epoch=" as *u8); gv_num(stamped_ts) 256 gv_puts(" window=[" as *u8); gv_num(t_before); gv_puts("," as *u8); gv_num(t_after); gv_puts("]\n" as *u8) 257 gv_check("heartbeat-carries-THIS-run-s-epoch-not-zero-and-not-a-fossil" as *u8, c4, ctr) 258 259 // ================= T5-T6 the exact bug being fixed: a MISSING pattern ========================== 260 // The path below is the one T2 just proved this organ can write, so its absence here is a fact 261 // about the failing run and not about an unwritable fixture. 262 sys_unlinkat(stamp) 263 let p2: i64 = hpg_respond_once(l_ok, r200, n200) 264 let rc_pat: i64 = hp_run(HPG_PORT_OK, "/api/cap/status" as *u8, need_false, HPG_BUDGET_SEC, stamp, HPG_TRACE_OFF) 265 hpg_reap(p2) 266 var c5: i64 = 0 267 if rc_pat == HP_EXIT_PATTERN_ABSENT { c5 = 1 } 268 gv_check("neg-control-live-endpoint-WITHOUT-the-marker-exits-3-pattern-absent" as *u8, c5, ctr) 269 var c6: i64 = 0 270 if hpg_exists(stamp) == 0 { c6 = 1 } 271 gv_check("neg-control-pattern-absent-leaves-NO-heartbeat-so-the-watch-goes-STALE" as *u8, c6, ctr) 272 273 // ================= T7-T8 status conjunct, isolated ============================================ 274 sys_unlinkat(stamp) 275 let p3: i64 = hpg_respond_once(l_500, r500, n500) 276 let rc_500: i64 = hp_run(HPG_PORT_500, "/api/cap/status" as *u8, need_true, HPG_BUDGET_SEC, stamp, HPG_TRACE_OFF) 277 hpg_reap(p3) 278 var c7: i64 = 0 279 if rc_500 == HP_EXIT_STATUS_NOT_2XX { c7 = 1 } 280 gv_check("neg-control-500-with-a-MATCHING-marker-still-exits-4-status-not-2xx" as *u8, c7, ctr) 281 var c8: i64 = 0 282 if hpg_exists(stamp) == 0 { c8 = 1 } 283 gv_check("neg-control-non-2xx-leaves-NO-heartbeat" as *u8, c8, ctr) 284 285 // ================= T9-T10 nothing listening =================================================== 286 sys_unlinkat(stamp) 287 let rc_conn: i64 = hp_run(HPG_PORT_CLOSED, "/api/cap/status" as *u8, need_true, HPG_BUDGET_SEC, stamp, HPG_TRACE_OFF) 288 var c9: i64 = 0 289 if rc_conn == HP_EXIT_CONNECT_FAILED { c9 = 1 } 290 gv_check("neg-control-unreachable-endpoint-exits-2-connect-failed-not-3-not-4" as *u8, c9, ctr) 291 var c10: i64 = 0 292 if hpg_exists(stamp) == 0 { c10 = 1 } 293 gv_check("neg-control-unreachable-endpoint-leaves-NO-heartbeat" as *u8, c10, ctr) 294 295 // ================= T11-T13 ACCEPTED THEN SILENT -- the 2026-08-06 shape ======================= 296 // A listening socket with nobody accepting still completes the TCP handshake out of the backlog, so 297 // connect() SUCCEEDS and the response never comes. That is a wedged daemon, and it is the case an 298 // unbounded read loop can never report -- it parks forever and a */5 beat piles up processes. 299 sys_unlinkat(stamp) 300 let h0: i64 = nx_clock_monotonic_ns() 301 let rc_hang: i64 = hp_run(HPG_PORT_HANG, "/api/cap/status" as *u8, need_true, HPG_BUDGET_SEC, stamp, HPG_TRACE_OFF) 302 let h1: i64 = nx_clock_monotonic_ns() 303 var hel: i64 = 0 - 1 304 if h0 > 0 { if h1 > 0 { hel = (h1 - h0) / HPG_NS_PER_MS } } 305 var c11: i64 = 0 306 if rc_hang == HP_EXIT_RECV_TIMEOUT { c11 = 1 } 307 gv_check("neg-control-accepted-but-silent-endpoint-exits-6-recv-timeout" as *u8, c11, ctr) 308 var c12: i64 = 0 309 if hpg_exists(stamp) == 0 { c12 = 1 } 310 gv_check("neg-control-recv-timeout-leaves-NO-heartbeat" as *u8, c12, ctr) 311 gv_puts(" wedged-endpoint probe returned after " as *u8); gv_num(hel) 312 gv_puts(" ms (an unbounded read never returns at all)\n" as *u8) 313 var c13: i64 = 0 314 if hel >= HPG_HANG_MIN_MS { if hel <= HPG_HANG_MAX_MS { c13 = 1 } } 315 gv_check("the-read-leg-is-BOUNDED-measured-in-ms-not-taken-on-the-return-code-s-word" as *u8, c13, ctr) 316 317 // ================= T14 a stamp that CANNOT be written must say so ============================= 318 let p4: i64 = hpg_respond_once(l_ok, r200, n200) 319 let rc_wr: i64 = hp_run(HPG_PORT_OK, "/api/cap/status" as *u8, need_true, HPG_BUDGET_SEC, badstamp, HPG_TRACE_OFF) 320 hpg_reap(p4) 321 var c14: i64 = 0 322 if rc_wr == HP_EXIT_STAMP_WRITE_FAILED { c14 = 1 } 323 gv_check("neg-control-an-unwritable-heartbeat-path-exits-5-instead-of-a-silent-no-op" as *u8, c14, ctr) 324 325 // ================= T15 ANTI-VACUITY: distinct outcomes, not one bucket ======================== 326 // The trivial wrong implementation this kills is the one that collapses every failure into a single 327 // code -- which is what the curl row did (it had exactly one observable outcome: nothing). 328 var c15: i64 = 1 329 if rc_ok == rc_pat { c15 = 0 } 330 if rc_ok == rc_500 { c15 = 0 } 331 if rc_ok == rc_conn { c15 = 0 } 332 if rc_ok == rc_hang { c15 = 0 } 333 if rc_ok == rc_wr { c15 = 0 } 334 if rc_pat == rc_500 { c15 = 0 } 335 if rc_pat == rc_conn { c15 = 0 } 336 if rc_pat == rc_hang { c15 = 0 } 337 if rc_pat == rc_wr { c15 = 0 } 338 if rc_500 == rc_conn { c15 = 0 } 339 if rc_500 == rc_hang { c15 = 0 } 340 if rc_500 == rc_wr { c15 = 0 } 341 if rc_conn == rc_hang { c15 = 0 } 342 if rc_conn == rc_wr { c15 = 0 } 343 if rc_hang == rc_wr { c15 = 0 } 344 gv_check("anti-vacuity-six-different-conditions-produced-six-pairwise-distinct-exit-codes" as *u8, c15, ctr) 345 346 // ================= T16-T17 every code NAMES a reason, and only the unknown one says unknown ==== 347 var c16: i64 = 1 348 var i: i64 = 0 349 while i <= HP_EXIT_NOT_HTTP { 350 if hp_streq(hp_reason(i), "unknown" as *u8) == 1 { c16 = 0 } 351 var j: i64 = i + 1 352 while j <= HP_EXIT_NOT_HTTP { 353 if hp_streq(hp_reason(i), hp_reason(j)) == 1 { c16 = 0 } 354 j = j + 1 355 } 356 i = i + 1 357 } 358 gv_check("every-declared-exit-code-carries-its-own-distinct-named-reason" as *u8, c16, ctr) 359 var c17: i64 = 0 360 if hp_streq(hp_reason(HPG_BAD_CODE), "unknown" as *u8) == 1 { c17 = 1 } 361 gv_check("neg-control-an-UNDECLARED-code-reports-unknown-rather-than-borrowing-a-real-reason" as *u8, c17, ctr) 362 363 // ================= T18-T19 the status parser is derived, and it refuses non-HTTP ============== 364 let synth: *u8 = sys_mmap(HPG_BUF) 365 var so: i64 = hpg_cat(synth, 0, "HTTP/1.0 204 No Content\r\n\r\n" as *u8) 366 var c18: i64 = 0 367 if hp_status_of(synth, so) == 204 { c18 = 1 } 368 gv_check("status-parse-is-derived-from-the-prefix-so-it-also-reads-HTTP-1-0" as *u8, c18, ctr) 369 let junk: *u8 = sys_mmap(HPG_BUF) 370 let jo: i64 = hpg_cat(junk, 0, "SSH-2.0-OpenSSH_9.2\r\n" as *u8) 371 var c19: i64 = 0 372 if hp_status_of(junk, jo) < 0 { c19 = 1 } 373 gv_check("neg-control-a-non-HTTP-reply-is-REFUSED-not-parsed-into-a-plausible-number" as *u8, c19, ctr) 374 375 // ================= T20 THE STDERR ANNOUNCE, WHICH IS THE WHOLE POINT ========================== 376 // The retired cron row sent stdout to a log and its own failure to nowhere. A replacement whose 377 // failure is visible ONLY to a caller who kept stdout inherits that defect exactly. So: rebind fd 2 378 // to a file, run one FAILING and one CLEAN fixture through it, and require the marker to appear for 379 // the first and NOT for the second. gv_bite scores both directions at once, because a channel that 380 // shouts on every run is as useless as one that never shouts. 381 let errcap: *u8 = "/tmp/nx_http_probe_gate/stderr.cap" as *u8 382 let errcap2: *u8 = "/tmp/nx_http_probe_gate/stderr2.cap" as *u8 383 sys_unlinkat(errcap) 384 sys_unlinkat(errcap2) 385 // gv_bite's contract: `bad` must be 1 (the detector fired on the crafted bad input) and `good` 386 // must be 0 (it stayed silent on the crafted good one). Both are counts of the SAME event -- did 387 // a FAIL marker reach stderr -- so neither can be satisfied by an always-on or always-off channel. 388 var bad_shouts: i64 = 0 389 var good_shouts: i64 = 0 390 391 let saved_err: i64 = sys_dup3(HPG_FD_STDERR, HPG_FD_ERRSAVE, 0) 392 let ec1: i64 = sys_openat_wr(errcap, HP_MODE_0644) 393 if ec1 >= 0 { 394 sys_dup3(ec1, HPG_FD_STDERR, 0) 395 let p5: i64 = hpg_respond_once(l_ok, r200, n200) 396 hp_run(HPG_PORT_OK, "/api/cap/status" as *u8, need_false, HPG_BUDGET_SEC, badstamp, HPG_TRACE_OFF) 397 hpg_reap(p5) 398 sys_close(ec1) 399 } 400 let ec2: i64 = sys_openat_wr(errcap2, HP_MODE_0644) 401 if ec2 >= 0 { 402 sys_dup3(ec2, HPG_FD_STDERR, 0) 403 sys_unlinkat(stamp) 404 let p6: i64 = hpg_respond_once(l_ok, r200, n200) 405 hp_run(HPG_PORT_OK, "/api/cap/status" as *u8, need_true, HPG_BUDGET_SEC, stamp, HPG_TRACE_OFF) 406 hpg_reap(p6) 407 sys_close(ec2) 408 } 409 if saved_err >= 0 { sys_dup3(HPG_FD_ERRSAVE, HPG_FD_STDERR, 0) } 410 411 let eb: *u8 = sys_mmap(HPG_BUF) 412 let en1: i64 = hpg_slurp(errcap, eb, HPG_BUF) 413 if en1 > 0 { if hp_contains(eb, en1, "verdict=FAIL reason=pattern-absent" as *u8) == 1 { bad_shouts = 1 } } 414 let en2: i64 = hpg_slurp(errcap2, eb, HPG_BUF) 415 if en2 > 0 { if hp_contains(eb, en2, "verdict=FAIL" as *u8) == 1 { good_shouts = 1 } } 416 gv_puts(" stderr bytes on the failing run=" as *u8); gv_num(en1) 417 gv_puts(" on the clean run=" as *u8); gv_num(en2); gv_puts("\n" as *u8) 418 gv_bite("a-failing-run-NAMES-its-reason-on-stderr-which-survives-stdout-to-dev-null" as *u8, bad_shouts, good_shouts, ctr) 419 420 sys_close(l_ok) 421 sys_close(l_500) 422 sys_close(l_hang) 423 sys_unlinkat(stamp) 424 425 let rc: i64 = gv_verdict("HTTP-PROBE-GATE" as *u8, ctr, "each tooth name carries its own strength; read the vector, not this line" as *u8) 426 sys_exit(rc) 427 return rc 428}