code wiki / _hdl_build / nx_routeguard_gate.nx
nx_routeguard_gate.nx source
↩ module page · 103 lines · 5225 B
1// nx_routeguard_gate.nx -- proves the deploy-contract guard DETECTS a vanished route and does NOT
2// cry wolf on a legitimate feature deploy. Synthetic images, so the answer is known by construction.
3// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
4import "nx_routeguard_lib.nx"
5import "nx_gate.nx"
6
7func rgg_num(v: i64) -> i64 {
8 let b: *u8 = sys_mmap(32)
9 if v == 0 { b[0] = 48 as u8; sys_write(1, b, 1); return 0 }
10 let t: *u8 = sys_mmap(32)
11 var n: i64 = 0
12 var x: i64 = v
13 while x > 0 { t[n] = ((x % 10) + 48) as u8; x = x / 10; n = n + 1 }
14 var o: i64 = 0
15 while n > 0 { n = n - 1; b[o] = t[n]; o = o + 1 }
16 sys_write(1, b, o)
17 return 0
18}
19
20func rgg_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
21
22func main() -> i64 {
23 gw("=== nx_routeguard_gate: deploy contract (route superset) ===\n" as *u8)
24 var pass: i64 = 0
25 var tot: i64 = 0
26
27 let lnames: *u8 = sys_mmap(RG_MAXR * RG_NAMEMAX)
28 let llens: *i64 = sys_mmap(RG_MAXR * 8) as *i64
29 let trunc: *i64 = sys_mmap(16) as *i64
30 let miss: *i64 = sys_mmap(RG_MAXR * 8) as *i64
31
32 // A synthetic "live" image carrying the real shape: a route-list literal plus dispatch literals.
33 let live: *u8 = "\"routes\":[\"/api/health\",\"/api/build\",\"/api/gate_run\",\"/api/proc_kill\",\"/api/deploy\"] dispatch /api/gate_run /api/proc_kill" as *u8
34 let ln: i64 = rgg_len(live)
35 let lcnt: i64 = rg_extract(live, ln, lnames, llens, trunc)
36
37 // T1: extraction finds the distinct routes and DEDUPES the dispatch repeats
38 tot = tot + 1
39 var t1: i64 = 0
40 if lcnt == 5 { if trunc[0] == 0 { t1 = 1 } }
41 if t1 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
42 gw("T1 extract: 5 distinct /api/ routes recovered from a binary image, repeats deduped\n" as *u8)
43
44 // T2 THE REGRESSION: a candidate MISSING gate_run + proc_kill -- the exact 21->19 loss, 5x live.
45 let bad: *u8 = "\"routes\":[\"/api/health\",\"/api/build\",\"/api/deploy\"] dispatch" as *u8
46 let m2: i64 = rg_missing(lnames, llens, lcnt, bad, rgg_len(bad), miss, RG_MAXR)
47 tot = tot + 1
48 var t2: i64 = 0
49 if m2 == 2 { t2 = 1 }
50 if t2 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
51 gw("T2 REGRESSION CAUGHT: candidate dropping gate_run+proc_kill reports exactly 2 missing\n" as *u8)
52
53 // T3 NEG-CONTROL, the cry-wolf test: an IDENTICAL candidate must report ZERO missing.
54 let m3: i64 = rg_missing(lnames, llens, lcnt, live, ln, miss, RG_MAXR)
55 tot = tot + 1
56 var t3: i64 = 0
57 if m3 == 0 { t3 = 1 }
58 if t3 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
59 gw("T3 NEG: an identical candidate reports 0 missing (no false alarm on a no-op deploy)\n" as *u8)
60
61 // T4 ASYMMETRY: a candidate that ADDS a route is FINE. Only disappearance is a defect --
62 // otherwise every legitimate feature deploy would be blocked and the guard would be disabled.
63 let more: *u8 = "\"routes\":[\"/api/health\",\"/api/build\",\"/api/gate_run\",\"/api/proc_kill\",\"/api/deploy\",\"/api/brandnew\"]" as *u8
64 let m4: i64 = rg_missing(lnames, llens, lcnt, more, rgg_len(more), miss, RG_MAXR)
65 tot = tot + 1
66 var t4: i64 = 0
67 if m4 == 0 { t4 = 1 }
68 if t4 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
69 gw("T4 ASYMMETRY: a candidate ADDING a route is not a regression (superset, not equality)\n" as *u8)
70
71 // T5 RENAME MUST NOT PASS: /api/health is GONE if only /api/healthcheck remains. A plain substring
72 // scan blesses this silently, which would let a rename erase a route while the guard says 0 missing.
73 // This tooth failed-as-designed on the first build and drove the boundary check in rg_contains.
74 let ren: *u8 = "\"routes\":[\"/api/healthcheck\",\"/api/build\",\"/api/gate_run\",\"/api/proc_kill\",\"/api/deploy\"]" as *u8
75 let m5: i64 = rg_missing(lnames, llens, lcnt, ren, rgg_len(ren), miss, RG_MAXR)
76 tot = tot + 1
77 var t5: i64 = 0
78 if m5 == 1 { t5 = 1 }
79 if t5 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
80 gw("T5 RENAME CAUGHT: /api/healthcheck does NOT satisfy /api/health (boundary-checked, not substring)\n" as *u8)
81
82 // T6 EMPTY-LIVE REFUSAL: extracting from an image with no routes yields 0, and the CALLER must
83 // refuse rather than report "0 missing = safe" -- guarding against nothing is not a guarantee.
84 let none: *u8 = "no routes here at all" as *u8
85 let lc6: i64 = rg_extract(none, rgg_len(none), lnames, llens, trunc)
86 tot = tot + 1
87 var t6: i64 = 0
88 if lc6 == 0 { t6 = 1 }
89 if t6 == 1 { pass = pass + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
90 gw("T6 REFUSAL INPUT: an image with no /api/ literals extracts 0 routes (caller must REFUSE)\n" as *u8)
91
92 gw("\n=== nx_routeguard_gate " as *u8)
93 rgg_num(pass)
94 gw("/" as *u8)
95 rgg_num(tot)
96 gw(" ===\n" as *u8)
97 if pass == tot {
98 gw("ROUTEGUARD GREEN -- catches the 5x mgmt route loss, no false alarm on add-or-noop\n" as *u8)
99 return 0
100 }
101 gw("ROUTEGUARD RED\n" as *u8)
102 return 1
103}