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}