nx_cap_issue_gate.nx source
↩ module page · 101 lines · 5825 B
1// nx_cap_issue_gate.nx -- proves the self-service DELEGATION endpoint (POST /api/cap/issue) over R0's ta_handle:
2// delegating narrows (the delegated cap grants the subset, not the dropped tool), widening is REFUSED, and a
3// forged presenter cap is REFUSED. Drives ta_handle_pfx in-process. license_tier: ORIGINAL
4import "nx_tools_api.nx"
5import "nx_gate.nx"
6
7func ig_has(o: *u8, n: i64, ndl: *u8) -> i64 { if ta_indexof(o, n, ndl) >= 0 { return 1 } return 0 }
8func ig_mark(cond: i64, p: *i64, t: *i64, lbl: *u8) -> i64 {
9 t[0] = t[0] + 1
10 if cond == 1 { p[0] = p[0] + 1; gw(" [PASS] " as *u8) } else { gw(" [FAIL] " as *u8) }
11 gw(lbl); gw("\n" as *u8)
12 return 0
13}
14func ig_issue_req(cap: *u8, caplen: i64, allow: *u8, out: *u8) -> i64 {
15 var o: i64 = ta_cat(out, 0, "POST /api/cap/issue HTTP/1.1\r\nHost: x\r\nX-Nishi-Cap: " as *u8)
16 o = ta_catb(out, o, cap, caplen)
17 o = ta_cat(out, o, "\r\nConnection: close\r\n\r\n{\"allow\":\"" as *u8)
18 o = ta_cat(out, o, allow)
19 o = ta_cat(out, o, "\",\"exp\":9999999999}" as *u8)
20 return o
21}
22func ig_call_req(cap: *u8, caplen: i64, name: *u8, out: *u8) -> i64 {
23 var o: i64 = ta_cat(out, 0, "POST /mcp HTTP/1.1\r\nHost: x\r\nConnection: close\r\n\r\n{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\"params\":{\"name\":\"" as *u8)
24 o = ta_cat(out, o, name)
25 o = ta_cat(out, o, "\",\"_cap\":\"" as *u8)
26 o = ta_catb(out, o, cap, caplen)
27 o = ta_cat(out, o, "\"}}" as *u8)
28 return o
29}
30// extract the "cap" value from a /api/cap/issue response into (off,len) relative to resp. 1/0.
31func ig_extract(resp: *u8, n: i64, ol: *i64) -> i64 {
32 let bo: i64 = ta_body_off(resp, n)
33 let body: *u8 = ((resp as i64) + bo) as *u8
34 let bn: i64 = n - bo
35 let cb: *i64 = sys_mmap(16) as *i64
36 if ta_json_str(body, bn, "\"cap\"" as *u8, cb) == 1 { ol[0] = bo + cb[0]; ol[1] = cb[1]; return 1 }
37 return 0
38}
39
40func main() -> i64 {
41 gw("=== nx_cap_issue_gate: self-service capability DELEGATION (ocap: subset-only, widening refused) ===\n" as *u8)
42 let TP: *u8 = "knowledge/toolreg-test-iss-" as *u8
43 let secret: *u8 = TA_CAP_SECRET
44 let slen: i64 = ta_slen(TA_CAP_SECRET)
45 let p: *i64 = sys_mmap(16) as *i64; p[0] = 0
46 let t: *i64 = sys_mmap(16) as *i64; t[0] = 0
47 let out: *u8 = sys_mmap(1048576)
48 let req: *u8 = sys_mmap(4096)
49 let ol: *i64 = sys_mmap(16) as *i64
50
51 let rootb: *u8 = sys_mmap(1024)
52 let root: i64 = capt_issue(secret, slen, "nx_a,nx_b" as *u8, 9, 9999999999, 1, rootb, 1024)
53
54 // Iss1: delegate {a,b} -> {a}. The delegated cap must GRANT nx_a (tools/call invoked) and DENY nx_b (narrowed).
55 let r1: i64 = ig_issue_req(rootb, root, "nx_a" as *u8, req)
56 let n1: i64 = ta_handle_pfx(TP, req, r1, out)
57 var t1: i64 = 0
58 if ig_extract(out, n1, ol) == 1 {
59 let dcap: *u8 = sys_mmap(1024); var c: i64 = 0; while c < ol[1] { dcap[c] = out[ol[0] + c]; c = c + 1 }
60 let dl: i64 = ol[1]
61 let ra: i64 = ig_call_req(dcap, dl, "nx_a" as *u8, req); let na: i64 = ta_handle_pfx(TP, req, ra, out)
62 // post-R2-exec-rung: a granted cap on a non-GREEN-allowlisted tool terminates at the
63 // "capability-authorized ..." tool result (only reachable when the delegated cap VERIFIED)
64 var ga: i64 = 0; if ig_has(out, na, "capability-authorized" as *u8) == 1 { if ig_has(out, na, "-32001" as *u8) == 0 { ga = 1 } }
65 let rb: i64 = ig_call_req(dcap, dl, "nx_b" as *u8, req); let nb: i64 = ta_handle_pfx(TP, req, rb, out)
66 var db: i64 = 0; if ig_has(out, nb, "-32001" as *u8) == 1 { db = 1 }
67 if ga == 1 { if db == 1 { t1 = 1 } }
68 }
69 ig_mark(t1, p, t, "Iss1 delegate {a,b}->{a}: delegated cap GRANTS a, DENIES b (narrowed + usable)" as *u8)
70
71 // Iss2: request {a,c} where c is NOT in the presenter's grant -> REFUSED (no widening).
72 let r2: i64 = ig_issue_req(rootb, root, "nx_a,nx_c" as *u8, req)
73 let n2: i64 = ta_handle_pfx(TP, req, r2, out)
74 var t2: i64 = 0; if ig_has(out, n2, "cannot delegate" as *u8) == 1 { t2 = 1 }
75 ig_mark(t2, p, t, "Iss2 request {a,c} (c not held) -> REFUSED (no widening; escalation blocked)" as *u8)
76
77 // Iss3: forged presenter cap -> REFUSED.
78 let fb: *u8 = sys_mmap(1024)
79 let froot: i64 = capt_issue("WRONG-forger-key-9999999999999999xy" as *u8, 35, "nx_a" as *u8, 4, 9999999999, 1, fb, 1024)
80 let r3: i64 = ig_issue_req(fb, froot, "nx_a" as *u8, req)
81 let n3: i64 = ta_handle_pfx(TP, req, r3, out)
82 var t3: i64 = 0; if ig_has(out, n3, "cannot delegate" as *u8) == 1 { t3 = 1 }
83 ig_mark(t3, p, t, "Iss3 FORGED presenter cap -> REFUSED (unforgeable input)" as *u8)
84
85 // Iss4: exp-clamp -- parent exp=1000; the endpoint request asks exp=9999999999 -> the delegated cap MUST be clamped
86 // to <= parent (so it is EXPIRED at now=2000, NOT silently extended to the far future).
87 let pb2: *u8 = sys_mmap(1024)
88 let root2: i64 = capt_issue(secret, slen, "nx_a,nx_b" as *u8, 9, 1000, 5, pb2, 1024)
89 let r4: i64 = ig_issue_req(pb2, root2, "nx_a" as *u8, req)
90 let n4: i64 = ta_handle_pfx(TP, req, r4, out)
91 var t4: i64 = 0
92 if ig_extract(out, n4, ol) == 1 {
93 let dc: *u8 = sys_mmap(1024); var cc: i64 = 0; while cc < ol[1] { dc[cc] = out[ol[0] + cc]; cc = cc + 1 }
94 if capt_verify(secret, slen, dc, ol[1], "nx_a" as *u8, 4, 2000) == CAPT_DENY_EXP { t4 = 1 }
95 }
96 ig_mark(t4, p, t, "Iss4 delegate exp > parent -> CLAMPED to parent (delegated cap EXPIRED at now=2000, not extended)" as *u8)
97
98 gw("\n=== nx_cap_issue_gate " as *u8); gn(p[0]); gw("/" as *u8); gn(t[0]); gw(" ===\n" as *u8)
99 if p[0] == t[0] { gw("CAP-ISSUE GREEN -- delegation narrows, widening + forgery refused (ocap delegation chain, no ambient identity)\n" as *u8); sys_exit(0); return 0 }
100 gw("CAP-ISSUE RED\n" as *u8); sys_exit(1); return 1
101}