code wiki / _hdl_build / nx_mgmt_api_gate.nx

nx_mgmt_api_gate.nx source

↩ module page · 330 lines · 18802 B

1// nx_mgmt_api_gate.nx -- SOVEREIGN in-process referee for the ecosystem control-plane API. NO socket, NO 2// curl, NO shell: arms a realm + registers an admin via the real Modern Auth, writes snapshot FIXTURES via 3// syscalls, then feeds crafted HTTP request BYTES straight into the pure router ma_handle and asserts the 4// response bytes. Proves the "true monitoring, no false +/-" property mechanically: 5// T1 GET /api -> 200 + route index (public) 6// T2 POST /api/login (correct) -> 200 + {"token":...} (mint no-cookie session) 7// T3 GET /api/health (degraded) +tok -> 200 DEGRADED + dueling-supervisors + crash-loop (no false-GREEN) 8// T4 GET /api/health NO tok -> 401 (infra state default-deny) 9// T5 GET /api/services(degraded) +tok -> 200 + the down/loop svc + "dup":1 (per-svc truth) 10// T6 POST /api/deploy NO tok -> 401 (privileged route GUARDED) 11// T7 POST /api/deploy +tok -> 501 (route reserved; honest, not faked) 12// T8 GET /api/health (healthy) +tok -> 200 + overall OK (no false-RED) 13// T9 GET /api/bogus -> 404 14// T10 GET /api/health (MISSING snap) +tok -> 200 + UNKNOWN + no-snapshot (no false-GREEN on absent data) 15// GREEN iff T1..T10 hold. Sovereign: nx_mgmt_api + nx_modern_auth_flow + nx_syscalls. license_tier: ORIGINAL 16import "nx_mgmt_api.nx" 17import "hub/nx_modern_auth_flow.nx" 18import "nx_syscalls.nx" 19 20func g_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 21func g_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 22func g_row(name: *u8, ok: i64) -> i64 { 23 if ok == 1 { g_w(" PASS " as *u8) } 24 if ok != 1 { g_w(" FAIL " as *u8) } 25 g_w(name) 26 g_w("\n" as *u8) 27 return ok 28} 29func 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 } 30func g_find(hay: *u8, hn: i64, ndl: *u8) -> i64 { var nl: i64=0; while ndl[nl]!=(0 as u8){nl=nl+1} if nl==0 { return 0-1 } var s: i64=0; while s+nl<=hn { var m: i64=1; var k: i64=0; while k<nl { if hay[s+k]!=ndl[k] { m=0; k=nl } else { k=k+1 } } if m==1 { return s } s=s+1 } return 0-1 } 31func g_cat_n(d: *u8, o: i64, s: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { d[o + i] = s[i]; i = i + 1 } return o + n } 32func g_trunc(path: *u8) -> i64 { let fd: i64 = sys_openat_wr(path, 0x180); if fd >= 0 { sys_close(fd) } return 0 } 33func g_log(s: *u8) -> i64 { 34 let fd: i64 = sys_openat_append("knowledge/status/mgmt_api_gate.log" as *u8, 0x1a4) 35 if fd >= 0 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); sys_close(fd) } 36 return 0 37} 38func g_write_file(path: *u8, s: *u8) -> i64 { 39 let fd: i64 = sys_openat_wr(path, 0x180) 40 if fd < 0 { return 0 - 1 } 41 sys_write(fd, s, g_len(s)) 42 sys_close(fd) 43 return 0 44} 45func g_starts(buf: *u8, n: i64, s: *u8) -> i64 { 46 let sn: i64 = g_len(s) 47 if n < sn { return 0 } 48 var i: i64 = 0 49 while i < sn { if (buf[i] as i64) != (s[i] as i64) { return 0 } i = i + 1 } 50 return 1 51} 52func g_contains(hay: *u8, n: i64, needle: *u8) -> i64 { 53 let nn: i64 = g_len(needle) 54 var i: i64 = 0 55 while i + nn <= n { 56 var m: i64 = 1 57 var j: i64 = 0 58 while j < nn { if (hay[i + j] as i64) != (needle[j] as i64) { m = 0; j = nn } else { j = j + 1 } } 59 if m == 1 { return 1 } 60 i = i + 1 61 } 62 return 0 63} 64func g_extract_token(resp: *u8, n: i64, out: *u8) -> i64 { 65 let key: *u8 = "{\"token\":\"" as *u8 66 let kn: i64 = 10 67 var start: i64 = 0 - 1 68 var i: i64 = 0 69 while i + kn <= n { 70 var m: i64 = 1 71 var j: i64 = 0 72 while j < kn { if (resp[i + j] as i64) != (key[j] as i64) { m = 0; j = kn } else { j = j + 1 } } 73 if m == 1 { start = i + kn; i = n } 74 i = i + 1 75 } 76 if start < 0 { return 0 } 77 var w: i64 = 0 78 var k: i64 = start 79 var done: i64 = 0 80 while done == 0 { 81 if k >= n { done = 1 } 82 if done == 0 { if (resp[k] as i64) == 34 { done = 1 } } 83 if done == 0 { out[w] = resp[k]; w = w + 1; k = k + 1 } 84 } 85 return w 86} 87 88func main() -> i64 { 89 g_w("mgmt-api SOVEREIGN in-process gate (no socket/curl/shell -- ma_handle bytes-in/bytes-out)\n" as *u8) 90 let store_path: *u8 = "/tmp/nx_ma_gate_store.log" as *u8 91 let keys_path: *u8 = "/tmp/nx_ma_gate_keys.log" as *u8 92 let deg: *u8 = "/tmp/nx_ma_degraded.snap" as *u8 93 let hea: *u8 = "/tmp/nx_ma_healthy.snap" as *u8 94 let miss: *u8 = "/tmp/nx_ma_missing.snap" as *u8 95 g_trunc(store_path) 96 g_trunc(keys_path) 97 98 // ---- snapshot fixtures via syscalls (NOT a shell). degraded = duel + dup + loop + down. ---- 99 if g_write_file(deg, "SUP 2\nSVC sites.elf 8443 UP 2 0 12\nSVC nx_gallery_serve 18090 DOWN 0 6 40\nSVC nx_vroom_daemon 0 HUNG 1 5 33\n" as *u8) != 0 { g_w("FIXTURE FAIL\n" as *u8); sys_exit(1) } 100 if g_write_file(hea, "SUP 1\nSVC sites.elf 8443 UP 1 0 3\nSVC nx_gallery_serve 18090 UP 1 0 4\n" as *u8) != 0 { g_w("FIXTURE FAIL\n" as *u8); sys_exit(1) } 101 // miss is deliberately NOT created. 102 103 // ---- arm a realm + register an admin via the real Modern Auth ---- 104 let oprf_seed: *u8 = sys_mmap(32) 105 let akp: *u8 = sys_mmap(32) 106 let akb: *u8 = sys_mmap(33) 107 let edp: *u8 = sys_mmap(32) 108 let edb: *u8 = sys_mmap(32) 109 if nx_uas_server_keys_load_or_init(keys_path, oprf_seed, akp, akb, edp, edb) != NX_UAS_OK { g_w("KEYS FAIL\n" as *u8); sys_exit(1) } 110 let realm: *u8 = "nishi_mgmt_admin" as *u8 111 let ctx: *NxAuthContext = sys_mmap(256) as *NxAuthContext 112 if nx_auth_context_init(ctx, realm, 16, realm, 16, store_path as i64, oprf_seed, edp, edb, 900, 8192, 1, 1, 5, 1) != NX_MAUTH_OK { g_w("CTX FAIL\n" as *u8); sys_exit(1) } 113 let mn: *u8 = sys_mmap(512) 114 let mn_n: *i64 = sys_mmap(16) as *i64 115 if nx_modern_auth_register(ctx, "elder" as *u8, 5, "correct horse battery staple" as *u8, 28, mn, 512, mn_n) != NX_MAUTH_OK { g_w("REGISTER FAIL\n" as *u8); sys_exit(1) } 116 117 let req: *u8 = sys_mmap(8192) 118 let out: *u8 = sys_mmap(SD_OUTCAP) 119 var pass: i64 = 0 120 121 // ---- T1: GET /api -> 200 + index ---- 122 var n1: i64 = g_cat(req, 0, "GET /api HTTP/1.1\r\nHost: x\r\n\r\n" as *u8) 123 let o1: i64 = ma_handle(ctx, req, n1, deg, out) 124 var t1: i64 = 0 125 if g_starts(out, o1, "HTTP/1.1 200" as *u8) == 1 { if g_contains(out, o1, "nishi-mgmt" as *u8) == 1 { t1 = 1 } } 126 pass = pass + g_row("T1 GET /api -> 200 + route index\x00" as *u8, t1) 127 128 // ---- T2: POST /api/login (correct) -> 200 + token ---- 129 var n2: i64 = g_cat(req, 0, "POST /api/login HTTP/1.1\r\nHost: x\r\n\r\nhandle=elder&passphrase=correct+horse+battery+staple" as *u8) 130 let o2: i64 = ma_handle(ctx, req, n2, deg, out) 131 var t2: i64 = 0 132 let tokbuf: *u8 = sys_mmap(256) 133 var tok_n: i64 = 0 134 if g_starts(out, o2, "HTTP/1.1 200" as *u8) == 1 { 135 tok_n = g_extract_token(out, o2, tokbuf) 136 if tok_n > 0 { t2 = 1 } 137 } 138 pass = pass + g_row("T2 POST /api/login ok -> 200 + token\x00" as *u8, t2) 139 140 // ---- T3: GET /api/health (degraded) WITH token -> 200 DEGRADED + duel + loop (no false-GREEN) ---- 141 var n3: i64 = g_cat(req, 0, "GET /api/health HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8) 142 n3 = g_cat_n(req, n3, tokbuf, tok_n) 143 n3 = g_cat(req, n3, "\r\n\r\n" as *u8) 144 let o3: i64 = ma_handle(ctx, req, n3, deg, out) 145 var t3: i64 = 0 146 if g_starts(out, o3, "HTTP/1.1 200" as *u8) == 1 { 147 if g_contains(out, o3, "\"overall\":\"DEGRADED\"" as *u8) == 1 { 148 if g_contains(out, o3, "dueling-supervisors" as *u8) == 1 { 149 if g_contains(out, o3, "crash-loop:" as *u8) == 1 { t3 = 1 } 150 } 151 } 152 } 153 pass = pass + g_row("T3 GET /api/health degraded -> DEGRADED + duel + crash-loop (no false-GREEN)\x00" as *u8, t3) 154 155 // ---- T4: GET /api/health NO token -> 401 ---- 156 var n4: i64 = g_cat(req, 0, "GET /api/health HTTP/1.1\r\nHost: x\r\n\r\n" as *u8) 157 let o4: i64 = ma_handle(ctx, req, n4, deg, out) 158 var t4: i64 = 0 159 if g_starts(out, o4, "HTTP/1.1 401" as *u8) == 1 { t4 = 1 } 160 pass = pass + g_row("T4 GET /api/health NO token -> 401 (default-deny)\x00" as *u8, t4) 161 162 // ---- T5: GET /api/services (degraded) WITH token -> 200 + svc truth ---- 163 var n5: i64 = g_cat(req, 0, "GET /api/services HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8) 164 n5 = g_cat_n(req, n5, tokbuf, tok_n) 165 n5 = g_cat(req, n5, "\r\n\r\n" as *u8) 166 let o5: i64 = ma_handle(ctx, req, n5, deg, out) 167 var t5: i64 = 0 168 if g_starts(out, o5, "HTTP/1.1 200" as *u8) == 1 { 169 if g_contains(out, o5, "nx_vroom_daemon" as *u8) == 1 { 170 if g_contains(out, o5, "\"dup\":1" as *u8) == 1 { t5 = 1 } 171 } 172 } 173 pass = pass + g_row("T5 GET /api/services degraded -> per-svc truth (dup flagged)\x00" as *u8, t5) 174 175 // ---- T6: POST /api/deploy NO token -> 401 (privileged guarded) ---- 176 var n6: i64 = g_cat(req, 0, "POST /api/deploy HTTP/1.1\r\nHost: x\r\n\r\n{}" as *u8) 177 let o6: i64 = ma_handle(ctx, req, n6, deg, out) 178 var t6: i64 = 0 179 if g_starts(out, o6, "HTTP/1.1 401" as *u8) == 1 { t6 = 1 } 180 pass = pass + g_row("T6 POST /api/deploy NO token -> 401 (privileged guarded)\x00" as *u8, t6) 181 182 // ---- T7: POST /api/deploy WITH token, NO target -> 400 (real handler, fail-closed; NOTHING promoted) ---- 183 var n7: i64 = g_cat(req, 0, "POST /api/deploy HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8) 184 n7 = g_cat_n(req, n7, tokbuf, tok_n) 185 n7 = g_cat(req, n7, "\r\n\r\n" as *u8) 186 let o7: i64 = ma_handle(ctx, req, n7, deg, out) 187 var t7: i64 = 0 188 if g_starts(out, o7, "HTTP/1.1 400" as *u8) == 1 { t7 = 1 } 189 pass = pass + g_row("T7 POST /api/deploy +token no-target -> 400 (real handler, fail-closed)\x00" as *u8, t7) 190 191 // ---- T8: GET /api/health (healthy) WITH token -> 200 + overall OK (no false-RED) ---- 192 var n8: i64 = g_cat(req, 0, "GET /api/health HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8) 193 n8 = g_cat_n(req, n8, tokbuf, tok_n) 194 n8 = g_cat(req, n8, "\r\n\r\n" as *u8) 195 let o8: i64 = ma_handle(ctx, req, n8, hea, out) 196 var t8: i64 = 0 197 if g_starts(out, o8, "HTTP/1.1 200" as *u8) == 1 { if g_contains(out, o8, "\"overall\":\"OK\"" as *u8) == 1 { t8 = 1 } } 198 pass = pass + g_row("T8 GET /api/health healthy -> overall OK (no false-RED)\x00" as *u8, t8) 199 200 // ---- T9: GET /api/bogus -> 404 ---- 201 var n9: i64 = g_cat(req, 0, "GET /api/bogus HTTP/1.1\r\nHost: x\r\n\r\n" as *u8) 202 let o9: i64 = ma_handle(ctx, req, n9, deg, out) 203 var t9: i64 = 0 204 if g_starts(out, o9, "HTTP/1.1 404" as *u8) == 1 { t9 = 1 } 205 pass = pass + g_row("T9 GET /api/bogus -> 404\x00" as *u8, t9) 206 207 // ---- T10: GET /api/health (MISSING snapshot) WITH token -> UNKNOWN + no-snapshot (no false-GREEN) ---- 208 var n10: i64 = g_cat(req, 0, "GET /api/health HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8) 209 n10 = g_cat_n(req, n10, tokbuf, tok_n) 210 n10 = g_cat(req, n10, "\r\n\r\n" as *u8) 211 let o10: i64 = ma_handle(ctx, req, n10, miss, out) 212 var t10: i64 = 0 213 if g_starts(out, o10, "HTTP/1.1 200" as *u8) == 1 { 214 if g_contains(out, o10, "\"overall\":\"UNKNOWN\"" as *u8) == 1 { 215 if g_contains(out, o10, "no-snapshot" as *u8) == 1 { t10 = 1 } 216 } 217 } 218 pass = pass + g_row("T10 GET /api/health MISSING snap -> UNKNOWN + no-snapshot (no false-GREEN)\x00" as *u8, t10) 219 220 // ---- T11: POST /api/deploy +token, UNKNOWN target -> 400 (fail-closed; not in allowlist, NOTHING promoted) ---- 221 var n11: i64 = g_cat(req, 0, "POST /api/deploy HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8) 222 n11 = g_cat_n(req, n11, tokbuf, tok_n) 223 n11 = g_cat(req, n11, "\r\n\r\ntarget=bogus_not_in_allowlist" as *u8) 224 let o11: i64 = ma_handle(ctx, req, n11, deg, out) 225 var t11: i64 = 0 226 if g_starts(out, o11, "HTTP/1.1 400" as *u8) == 1 { if g_contains(out, o11, "unknown target" as *u8) == 1 { t11 = 1 } } 227 pass = pass + g_row("T11 POST /api/deploy +token unknown-target -> 400 (allowlist fail-closed)\x00" as *u8, t11) 228 229 // ---- T12: md_resolve_target data-driven allowlist -- known -> 1, unknown -> 0 (unit, no deploy) ---- 230 let tcfg: *u8 = "/tmp/nx_ma_targets.conf" as *u8 231 g_write_file(tcfg, "# test allowlist\ngatetest 2 /tmp/nx_ma_nope_src deploy https://x.example\n" as *u8) 232 let kb: *i64 = sys_mmap(8) as *i64 233 let sbuf: *u8 = sys_mmap(512) 234 let ubuf: *u8 = sys_mmap(64) 235 let lbuf: *u8 = sys_mmap(256) 236 let rbb: *u8 = sys_mmap(64) 237 var t12: i64 = 0 238 if md_resolve_target(tcfg, "gatetest" as *u8, 0, 8, kb, sbuf, ubuf, lbuf, rbb) == 1 { 239 // legacy 5-field row -> rollback defaults to "rollback" 240 var rbok: i64 = 0; if rbb[0]==(114 as u8) { rbok = 1 } // 'r'ollback 241 if md_resolve_target(tcfg, "nope" as *u8, 0, 4, kb, sbuf, ubuf, lbuf, rbb) == 0 { if rbok==1 { t12 = 1 } } 242 } 243 pass = pass + g_row("T12 md_resolve_target: known->1 + unknown->0 + default rollback (data-driven allowlist)\x00" as *u8, t12) 244 245 // ---- T12b: /api/hostctl action allowlist is FAIL-CLOSED (safe subs ok; selfswap/arbitrary rejected) ---- 246 var t12b: i64 = 0 247 if md_hostctl_action_ok("torstat" as *u8) == 1 { if md_hostctl_action_ok("routerctl" as *u8) == 1 { if md_hostctl_action_ok("kicktorrent" as *u8) == 1 { 248 if md_hostctl_action_ok("selfswap" as *u8) == 0 { if md_hostctl_action_ok("rm" as *u8) == 0 { if md_hostctl_action_ok("deploy" as *u8) == 0 { t12b = 1 } } } } } } 249 pass = pass + g_row("T12b md_hostctl_action_ok: safe->1, selfswap/rm/deploy->0 (fail-closed)\x00" as *u8, t12b) 250 251 // ---- T12c: ma_openapi generates a well-formed OpenAPI 3.1 spec (Swagger-parity; machine-readable API) ---- 252 let ob: *u8 = sys_mmap(32768); let obn: i64 = ma_openapi(ob) 253 var t12c: i64 = 0 254 if g_find(ob, obn, "\"openapi\":\"3.1.0\"" as *u8) >= 0 { if g_find(ob, obn, "/api/hostctl" as *u8) >= 0 { 255 if g_find(ob, obn, "application/problem+json" as *u8) >= 0 { if g_find(ob, obn, "nishiSession" as *u8) >= 0 { t12c = 1 } } } } 256 pass = pass + g_row("T12c ma_openapi: OpenAPI 3.1 + paths + RFC9457 problem-schema + OPAQUE security scheme\x00" as *u8, t12c) 257 258 // ---- T13: POST /api/migrate +token -> 501 (still reserved; honest, R3b migration sub-arc) ---- 259 var n13: i64 = g_cat(req, 0, "POST /api/migrate HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8) 260 n13 = g_cat_n(req, n13, tokbuf, tok_n) 261 n13 = g_cat(req, n13, "\r\n\r\n" as *u8) 262 let o13: i64 = ma_handle(ctx, req, n13, deg, out) 263 var t13: i64 = 0 264 if g_starts(out, o13, "HTTP/1.1 501" as *u8) == 1 { t13 = 1 } 265 pass = pass + g_row("T13 POST /api/migrate +token -> 501 (still reserved, honest)\x00" as *u8, t13) 266 267 // ---- T14: POST /api/rollback NO token -> 401 (privileged guarded) ---- 268 var n14: i64 = g_cat(req, 0, "POST /api/rollback HTTP/1.1\r\nHost: x\r\n\r\nconfirm=yes" as *u8) 269 let o14: i64 = ma_handle(ctx, req, n14, deg, out) 270 var t14: i64 = 0 271 if g_starts(out, o14, "HTTP/1.1 401" as *u8) == 1 { t14 = 1 } 272 pass = pass + g_row("T14 POST /api/rollback NO token -> 401 (privileged guarded)\x00" as *u8, t14) 273 274 // ---- T15: POST /api/rollback +token, NO confirm -> 400 (no accidental rollback; not executed) ---- 275 var n15: i64 = g_cat(req, 0, "POST /api/rollback HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8) 276 n15 = g_cat_n(req, n15, tokbuf, tok_n) 277 n15 = g_cat(req, n15, "\r\n\r\n" as *u8) 278 let o15: i64 = ma_handle(ctx, req, n15, deg, out) 279 var t15: i64 = 0 280 if g_starts(out, o15, "HTTP/1.1 400" as *u8) == 1 { t15 = 1 } 281 pass = pass + g_row("T15 POST /api/rollback +token no-confirm -> 400 (no accidental rollback)\x00" as *u8, t15) 282 283 // ---- T16: POST /api/reconcile NO token -> 401 (privileged guarded) ---- 284 var n16: i64 = g_cat(req, 0, "POST /api/reconcile HTTP/1.1\r\nHost: x\r\n\r\nconfirm=yes" as *u8) 285 let o16: i64 = ma_handle(ctx, req, n16, deg, out) 286 var t16: i64 = 0 287 if g_starts(out, o16, "HTTP/1.1 401" as *u8) == 1 { t16 = 1 } 288 pass = pass + g_row("T16 POST /api/reconcile NO token -> 401 (privileged guarded)\x00" as *u8, t16) 289 290 // ---- T17: POST /api/reconcile +token, NO confirm -> 400 (no accidental supervisor kill; NOT executed) ---- 291 var n17: i64 = g_cat(req, 0, "POST /api/reconcile HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8) 292 n17 = g_cat_n(req, n17, tokbuf, tok_n) 293 n17 = g_cat(req, n17, "\r\n\r\n" as *u8) 294 let o17: i64 = ma_handle(ctx, req, n17, deg, out) 295 var t17: i64 = 0 296 if g_starts(out, o17, "HTTP/1.1 400" as *u8) == 1 { t17 = 1 } 297 pass = pass + g_row("T17 POST /api/reconcile +token no-confirm -> 400 (no accidental kill)\x00" as *u8, t17) 298 299 // ---- T18: POST /api/restart +token, UNKNOWN service -> 400 (fail-closed; NOT executed) ---- 300 var n18: i64 = g_cat(req, 0, "POST /api/restart HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8) 301 n18 = g_cat_n(req, n18, tokbuf, tok_n) 302 n18 = g_cat(req, n18, "\r\n\r\nservice=bogus&confirm=yes" as *u8) 303 let o18: i64 = ma_handle(ctx, req, n18, deg, out) 304 var t18: i64 = 0 305 if g_starts(out, o18, "HTTP/1.1 400" as *u8) == 1 { if g_contains(out, o18, "unknown service" as *u8) == 1 { t18 = 1 } } 306 pass = pass + g_row("T18 POST /api/restart +token unknown-service -> 400 (allowlist fail-closed)\x00" as *u8, t18) 307 308 // ---- T19: POST /api/restart +token, known service, NO confirm -> 400 (not executed) ---- 309 var n19: i64 = g_cat(req, 0, "POST /api/restart HTTP/1.1\r\nHost: x\r\nX-Nishi-Session: " as *u8) 310 n19 = g_cat_n(req, n19, tokbuf, tok_n) 311 n19 = g_cat(req, n19, "\r\n\r\nservice=reader" as *u8) 312 let o19: i64 = ma_handle(ctx, req, n19, deg, out) 313 var t19: i64 = 0 314 if g_starts(out, o19, "HTTP/1.1 400" as *u8) == 1 { t19 = 1 } 315 pass = pass + g_row("T19 POST /api/restart +token known-svc no-confirm -> 400 (no accidental restart)\x00" as *u8, t19) 316 317 // ---- T20: md_restart_sub allowlist -- known -> 1, unknown -> 0 (unit, no exec) ---- 318 let rsb: *u8 = sys_mmap(64) 319 var t20: i64 = 0 320 if md_restart_sub("reader" as *u8, 0, 6, rsb) == 1 { 321 if md_restart_sub("bogus" as *u8, 0, 5, rsb) == 0 { t20 = 1 } 322 } 323 pass = pass + g_row("T20 md_restart_sub: known->1 + unknown->0 (data-driven allowlist)\x00" as *u8, t20) 324 325 if pass == 20 { g_log("MGMT-API-GATE pass=20/20 verdict=GREEN\n" as *u8); g_w("MGMT-API GATE GREEN 20/20 (spine + true-monitoring + deploy/rollback + reconcile/restart wired, all fail-closed, no false +/-)\n" as *u8); sys_exit(0) } 326 g_log("MGMT-API-GATE verdict=RED\n" as *u8) 327 g_w("MGMT-API GATE RED\n" as *u8) 328 sys_exit(1) 329 return 1 330}