code wiki / _hdl_build / nx_mgmt_cap_mint_gate.nx
nx_mgmt_cap_mint_gate.nx source
↩ module page · 140 lines · 7681 B
1// nx_mgmt_cap_mint_gate.nx -- prove POST /api/cap/mint is fail-closed least-authority. In-process referee
2// (no socket): crafts request BYTES, feeds the pure handler ma_do_cap_mint. Auth is the SAME ma_level_of
3// gate as every other write route, so this focuses on the NEW logic:
4// T1 missing allow -> 400
5// T2 allow=* -> 400 (charset refuses the mint-everything cap BY CONSTRUCTION)
6// T3 malformed csv (a,,b) -> 400
7// T4 allow names an UNREGISTERED tool -> 400 (a cap can never pre-authorize a phantom tool)
8// T5 no confirm=yes -> 400
9// T6 days out of range -> 400
10// T7 FAIL-CLOSED oracle: valid multi-element allow + confirm, but the on-NAS minter elf is absent locally
11// -> oracle exit != 0 -> 400 "mint failed", NO token, and NO cap_consent.log audit line (nothing minted).
12// (The positive mint is proven LIVE post-deploy -- the oracle + keyfile are NAS-absolute by design.)
13// Runs FS under /tmp. license_tier: ORIGINAL expect_exit: 0
14import "nx_mgmt_api.nx"
15import "nx_syscalls.nx"
16
17func w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
18func pn(v: i64) -> i64 {
19 let b: *u8 = sys_mmap(32) as *u8
20 var x: i64 = v; if x < 0 { sys_write(1,"-" as *u8,1); x = 0 - x }
21 var i: i64 = 31
22 if x == 0 { b[i] = 48 as u8; i = i - 1 }
23 while x > 0 { b[i] = (48 + x % 10) as u8; x = x / 10; i = i - 1 }
24 sys_write(1, (b as i64 + i + 1) as *u8, 31 - i)
25 return 0
26}
27func glen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
28func gcat(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 }
29func gcatn(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 }
30func gcontains(hay: *u8, n: i64, needle: *u8) -> i64 {
31 let nn: i64 = glen(needle)
32 var i: i64 = 0
33 while i + nn <= n {
34 var m: i64 = 1; var j: i64 = 0
35 while j < nn { if (hay[i+j] as i64) != (needle[j] as i64) { m = 0; j = nn } else { j = j + 1 } }
36 if m == 1 { return 1 }
37 i = i + 1
38 }
39 return 0
40}
41func mkreq(dst: *u8, line: *u8, bod: *u8) -> i64 {
42 let bn: i64 = glen(bod)
43 var o: i64 = gcat(dst, 0, line)
44 o = gcat(dst, o, " HTTP/1.1\r\nHost: x\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: " as *u8)
45 let t: *u8 = sys_mmap(24); var m: i64 = bn; var k: i64 = 0
46 if m == 0 { t[0]=48 as u8; k=1 }
47 while m > 0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
48 var z: i64 = 0
49 while z < k { dst[o]=t[k-1-z]; o=o+1; z=z+1 }
50 o = gcat(dst, o, "\r\n\r\n" as *u8)
51 o = gcatn(dst, o, bod, bn)
52 return o
53}
54func wfile(path: *u8, buf: *u8, n: i64) -> i64 {
55 let fd: i64 = sys_openat_wr(path, 0x1a4); if fd < 0 { return 0 - 1 }
56 sys_write(fd, buf, n); sys_close(fd); return 0
57}
58func fsize(path: *u8) -> i64 {
59 let szp: *i64 = sys_mmap(16) as *i64
60 let b: *u8 = sys_read_file(path, szp)
61 if (b as i64) == 0 { return 0 - 1 }
62 return szp[0]
63}
64
65func main() -> i64 {
66 w("=== nx_mgmt_cap_mint_gate -- POST /api/cap/mint, fail-closed least-authority ===\n" as *u8)
67 sys_mkdir("/tmp/nx_capm_gt" as *u8, 0x1ed)
68 sys_chdir("/tmp/nx_capm_gt" as *u8)
69 __syscall(263, 0-100, "cap_consent.log" as *u8, 0, 0, 0, 0) // unlinkat(AT_FDCWD, ., 0): fresh-run scrub (x86-64 263 passthrough)
70 let out: *u8 = sys_mmap(262144)
71 let req: *u8 = sys_mmap(262144)
72 var fails: i64 = 0
73
74 // seed an allowlist with two registered tools (multi-element allow-walk coverage in T7).
75 let seed: *u8 = "existingtool\t/x/y.elf\tGREEN\nsecondtool\t/x/z.elf\tGREEN\n" as *u8
76 wfile("tool_allowlist.conf" as *u8, seed, glen(seed))
77
78 // T1 missing allow
79 let n1: i64 = mkreq(req, "POST /api/cap/mint" as *u8, "confirm=yes" as *u8)
80 let r1: i64 = ma_do_cap_mint(req, n1, out)
81 var t1: i64 = 1
82 if gcontains(out, r1, "400" as *u8) == 0 { t1 = 0 }
83 if gcontains(out, r1, "missing allow" as *u8) == 0 { t1 = 0 }
84 if t1 == 1 { w("T1 PASS missing allow -> 400\n" as *u8) } else { fails = fails + 1; w("T1 FAIL\n" as *u8); sys_write(1, out, r1); w("\n" as *u8) }
85
86 // T2 allow=* refused (least-authority: no mint-everything cap)
87 let n2: i64 = mkreq(req, "POST /api/cap/mint" as *u8, "allow=*&confirm=yes" as *u8)
88 let r2: i64 = ma_do_cap_mint(req, n2, out)
89 var t2: i64 = 1
90 if gcontains(out, r2, "400" as *u8) == 0 { t2 = 0 }
91 if gcontains(out, r2, "invalid allow charset" as *u8) == 0 { t2 = 0 }
92 if t2 == 1 { w("T2 PASS allow=* -> 400 refused\n" as *u8) } else { fails = fails + 1; w("T2 FAIL\n" as *u8); sys_write(1, out, r2); w("\n" as *u8) }
93
94 // T3 malformed csv
95 let n3: i64 = mkreq(req, "POST /api/cap/mint" as *u8, "allow=existingtool,,secondtool&confirm=yes" as *u8)
96 let r3: i64 = ma_do_cap_mint(req, n3, out)
97 var t3: i64 = 1
98 if gcontains(out, r3, "400" as *u8) == 0 { t3 = 0 }
99 if gcontains(out, r3, "malformed allow csv" as *u8) == 0 { t3 = 0 }
100 if t3 == 1 { w("T3 PASS malformed csv -> 400\n" as *u8) } else { fails = fails + 1; w("T3 FAIL\n" as *u8); sys_write(1, out, r3); w("\n" as *u8) }
101
102 // T4 unregistered tool named -> 400 (caps only over tools that EXIST)
103 let n4: i64 = mkreq(req, "POST /api/cap/mint" as *u8, "allow=existingtool,ghosttool&confirm=yes" as *u8)
104 let r4: i64 = ma_do_cap_mint(req, n4, out)
105 var t4: i64 = 1
106 if gcontains(out, r4, "400" as *u8) == 0 { t4 = 0 }
107 if gcontains(out, r4, "unregistered tool: ghosttool" as *u8) == 0 { t4 = 0 }
108 if t4 == 1 { w("T4 PASS unregistered tool -> 400\n" as *u8) } else { fails = fails + 1; w("T4 FAIL\n" as *u8); sys_write(1, out, r4); w("\n" as *u8) }
109
110 // T5 no confirm
111 let n5: i64 = mkreq(req, "POST /api/cap/mint" as *u8, "allow=existingtool" as *u8)
112 let r5: i64 = ma_do_cap_mint(req, n5, out)
113 var t5: i64 = 1
114 if gcontains(out, r5, "400" as *u8) == 0 { t5 = 0 }
115 if gcontains(out, r5, "confirm=yes" as *u8) == 0 { t5 = 0 }
116 if t5 == 1 { w("T5 PASS no-confirm -> 400\n" as *u8) } else { fails = fails + 1; w("T5 FAIL\n" as *u8); sys_write(1, out, r5); w("\n" as *u8) }
117
118 // T6 days out of range
119 let n6: i64 = mkreq(req, "POST /api/cap/mint" as *u8, "allow=existingtool&days=9999&confirm=yes" as *u8)
120 let r6: i64 = ma_do_cap_mint(req, n6, out)
121 var t6: i64 = 1
122 if gcontains(out, r6, "400" as *u8) == 0 { t6 = 0 }
123 if gcontains(out, r6, "invalid days" as *u8) == 0 { t6 = 0 }
124 if t6 == 1 { w("T6 PASS days=9999 -> 400\n" as *u8) } else { fails = fails + 1; w("T6 FAIL\n" as *u8); sys_write(1, out, r6); w("\n" as *u8) }
125
126 // T7 FAIL-CLOSED oracle: fully valid request, but the NAS-absolute minter elf is absent locally.
127 // Expect 400 "mint failed", NO "MINTED", and NO consent-log line (an unminted cap leaves no audit).
128 let n7: i64 = mkreq(req, "POST /api/cap/mint" as *u8, "allow=existingtool,secondtool&days=30&confirm=yes" as *u8)
129 let r7: i64 = ma_do_cap_mint(req, n7, out)
130 var t7: i64 = 1
131 if gcontains(out, r7, "400" as *u8) == 0 { t7 = 0 }
132 if gcontains(out, r7, "mint failed" as *u8) == 0 { t7 = 0 }
133 if gcontains(out, r7, "MINTED" as *u8) == 1 { t7 = 0 }
134 if fsize("cap_consent.log" as *u8) != (0 - 1) { t7 = 0 }
135 if t7 == 1 { w("T7 PASS absent oracle -> 400 mint failed, no token, no audit line\n" as *u8) } else { fails = fails + 1; w("T7 FAIL\n" as *u8); sys_write(1, out, r7); w("\n" as *u8) }
136
137 if fails == 0 { w("MGMT-CAP-MINT-GATE 7/7 GREEN -- least-authority (star/charset/csv/registered-only) + fail-closed oracle + audit-only-on-mint\n" as *u8); sys_exit(0); return 0 }
138 w("MGMT-CAP-MINT-GATE RED fails=" as *u8); pn(fails); w("\n" as *u8)
139 sys_exit(1); return 1
140}