code wiki / (root) / nx_cap_invoke_gate.nx

nx_cap_invoke_gate.nx source

↩ module page · 89 lines · 5121 B

1// nx_cap_invoke_gate.nx -- proves R2: MCP tools/call over R0 is CAPABILITY-SCOPED. Drives ta_handle_pfx in-process 2// with POST /mcp tools/call requests carrying (or lacking) an X-Nishi-Cap token. The beyond-MCP property: invocation 3// requires an unforgeable capability that GRANTS THE SPECIFIC TOOL -- there is NO ambient authority, so confused-deputy 4// is structurally impossible. license_tier: ORIGINAL 5import "nx_tools_api.nx" // ta_handle_pfx + TA_CAP_SECRET + capt_issue/CAPT_OK (transitive) + ta_slen/ta_indexof 6import "nx_gate.nx" 7 8// build "POST /mcp ... tools/call {name:<tool>}" into out; include X-Nishi-Cap iff caplen>0. Returns length. 9func civ_req(cap: *u8, caplen: i64, tool: *u8, out: *u8) -> i64 { 10 var o: i64 = ta_cat(out, 0, "POST /mcp HTTP/1.1\r\nHost: x\r\n" as *u8) 11 if caplen > 0 { 12 o = ta_cat(out, o, "X-Nishi-Cap: " as *u8) 13 o = ta_catb(out, o, cap, caplen) 14 o = ta_cat(out, o, "\r\n" as *u8) 15 } 16 o = ta_cat(out, o, "Connection: close\r\n\r\n{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\"params\":{\"name\":\"" as *u8) 17 o = ta_cat(out, o, tool) 18 o = ta_cat(out, o, "\"}}" as *u8) 19 return o 20} 21func civ_has(out: *u8, n: i64, needle: *u8) -> i64 { if ta_indexof(out, n, needle) >= 0 { return 1 } return 0 } 22func civ_mark(cond: i64, pass: *i64, tot: *i64, label: *u8) -> i64 { 23 tot[0] = tot[0] + 1 24 if cond == 1 { pass[0] = pass[0] + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) } 25 gw(label); gw("\n" as *u8) 26 return 0 27} 28 29func main() -> i64 { 30 gw("=== nx_cap_invoke_gate: capability-scoped tools/call (R2 beyond MCP -- no ambient authority) ===\n" as *u8) 31 let TP: *u8 = "knowledge/toolreg-test-inv-" as *u8 32 let secret: *u8 = TA_CAP_SECRET 33 let slen: i64 = ta_slen(secret) 34 let pbox: *i64 = sys_mmap(16) as *i64; pbox[0] = 0 35 let tbox: *i64 = sys_mmap(16) as *i64; tbox[0] = 0 36 let out: *u8 = sys_mmap(1048576) 37 let reqb: *u8 = sys_mmap(4096) 38 39 // a capability granting ONLY nx_http_probe 40 let capb: *u8 = sys_mmap(1024) 41 let capn: i64 = capt_issue(secret, slen, "nx_http_probe" as *u8, 13, 9999999999, 1, capb, 1024) 42 43 // T1: WITH a valid cap for nx_http_probe -> AUTHORIZED (granted == CAPT_OK). Since the R2 exec rung, 44 // execution is a SEPARATE fail-closed layer (nx_tool_exec_allow); the deterministic gate-side terminal 45 // for an authorized-but-not-GREEN-runnable tool is the "capability-authorized ..." tool result -- that 46 // string is ONLY reachable when the capability verified, which is exactly this gate's concern. 47 let r1: i64 = civ_req(capb, capn, "nx_http_probe" as *u8, reqb) 48 let n1: i64 = ta_handle_pfx(TP, reqb, r1, out) 49 var t1: i64 = 0 50 if civ_has(out, n1, "capability-authorized" as *u8) == 1 { if civ_has(out, n1, "-32001" as *u8) == 0 { t1 = 1 } } 51 civ_mark(t1, pbox, tbox, "T1 valid capability for the tool -> AUTHORIZED (exec layer separate)" as *u8) 52 53 // T2: same probe-only cap, call a DIFFERENT tool -> DENIED (least authority: the cap doesn't grant it) 54 let r2: i64 = civ_req(capb, capn, "nx_mgmt_client" as *u8, reqb) 55 let n2: i64 = ta_handle_pfx(TP, reqb, r2, out) 56 var t2: i64 = 0 57 if civ_has(out, n2, "-32001" as *u8) == 1 { t2 = 1 } 58 civ_mark(t2, pbox, tbox, "T2 cap does NOT grant the requested tool -> DENIED (least authority)" as *u8) 59 60 // T3: NO capability at all -> DENIED (no ambient authority -- the beyond-MCP point) 61 let r3: i64 = civ_req(0 as *u8, 0, "nx_http_probe" as *u8, reqb) 62 let n3: i64 = ta_handle_pfx(TP, reqb, r3, out) 63 var t3: i64 = 0 64 if civ_has(out, n3, "-32001" as *u8) == 1 { t3 = 1 } 65 civ_mark(t3, pbox, tbox, "T3 NO capability -> DENIED (no ambient authority)" as *u8) 66 67 // T4: FORGED capability (minted with the wrong secret) -> DENIED (unforgeable) 68 let wk: *u8 = "WRONG-SECRET-NOT-THE-SERVERS-KEY-99999" as *u8 69 let fb: *u8 = sys_mmap(1024) 70 let fn: i64 = capt_issue(wk, ta_slen(wk), "nx_http_probe" as *u8, 13, 9999999999, 1, fb, 1024) 71 let r4: i64 = civ_req(fb, fn, "nx_http_probe" as *u8, reqb) 72 let n4: i64 = ta_handle_pfx(TP, reqb, r4, out) 73 var t4: i64 = 0 74 if civ_has(out, n4, "-32001" as *u8) == 1 { t4 = 1 } 75 civ_mark(t4, pbox, tbox, "T4 forged capability (wrong secret) -> DENIED (unforgeable)" as *u8) 76 77 // T5: EXPIRED capability -> DENIED (time-bound) 78 let eb: *u8 = sys_mmap(1024) 79 let en: i64 = capt_issue(secret, slen, "nx_http_probe" as *u8, 13, 1, 2, eb, 1024) 80 let r5: i64 = civ_req(eb, en, "nx_http_probe" as *u8, reqb) 81 let n5: i64 = ta_handle_pfx(TP, reqb, r5, out) 82 var t5: i64 = 0 83 if civ_has(out, n5, "-32001" as *u8) == 1 { t5 = 1 } 84 civ_mark(t5, pbox, tbox, "T5 expired capability -> DENIED (time-bound)" as *u8) 85 86 gw("\n=== nx_cap_invoke_gate " as *u8); gn(pbox[0]); gw("/" as *u8); gn(tbox[0]); gw(" ===\n" as *u8) 87 if pbox[0] == tbox[0] { gw("CAP-INVOKE GREEN -- tools/call is capability-scoped: authority-in-token, unforgeable, least-authority, time-bound (beyond MCP)\n" as *u8); sys_exit(0); return 0 } 88 gw("CAP-INVOKE RED\n" as *u8); sys_exit(1); return 1 89}