nx_tools_api_recovery_comparison_gate_v3_t316.nx source
↩ module page · 60 lines · 4525 B
1import "nx_tools_api_recovery_candidate_v3_t316.nx"
2func rc_has(b:*u8,n:i64,s:*u8)->i64{if ta_indexof(b,n,s)>=0{return 1};return 0}
3func rc_before(jb:*u8,bin:i64,nmp:*u8,nml:i64,granted:i64,capl:i64)->i64{
4 var b:i64=bin
5 // ACTIONABLE DENY (rule 18: say WHAT happened, WHY it matters, WHAT to do). The old text was a bare
6 // capability-denied-is-required, which a caller cannot distinguish from -- this tool does not exist --
7 // measured as the trigger for the ssh/PowerShell fallback cascade (debt seq1235). The two cases have
8 // OPPOSITE remedies, so they get OPPOSITE messages, and the presented flag states which one you are in.
9 b = ta_cat(jb, b, ",\"error\":{\"code\":-32001,\"message\":\"capability denied for tool '" as *u8)
10 b = ta_json_esc(jb, b, nmp, nml)
11 if capl <= 0 {
12 b = ta_cat(jb, b, "': NO capability was presented. This tool EXISTS and is callable -- this is an auth gap, NOT a missing tool, so do NOT fall back to shell/ssh. Present one of: ?cap=<token> on the MCP URL (session baseline, survives clients that drop custom headers), X-Nishi-Cap: <token>, Authorization: Bearer <token>, or params._cap in the call arguments (per-call override, wins over all others). Mint one with the management API POST /api/cap/mint allow=<tool>&confirm=yes with authorized admin credentials; optional days=<lifetime-days> and nonce=<positive-integer>. Signing-key status is GET /api/cap/status on this public tools API origin, not the management API." as *u8)
13 } else {
14 b = ta_cat(jb, b, "': the capability you DID present does not grant this tool, or is expired, forged, or revoked. Check its allow-list covers this exact tool name; mint a scoped one with the management API POST /api/cap/mint allow=<tool>&confirm=yes with authorized admin credentials; optional days=<lifetime-days> and nonce=<positive-integer>. Confirm signing-key status with GET /api/cap/status on this public tools API origin, not the management API. The tool itself exists -- do NOT fall back to shell/ssh." as *u8)
15 }
16 b = ta_cat(jb, b, "\",\"data\":{\"reason\":" as *u8)
17 b = ta_catn(jb, b, 0 - granted)
18 b = ta_cat(jb, b, ",\"presented\":" as *u8)
19 if capl > 0 { b = ta_cat(jb, b, "1" as *u8) } else { b = ta_cat(jb, b, "0" as *u8) }
20 b = ta_cat(jb, b, ",\"tool\":\"" as *u8)
21 b = ta_json_esc(jb, b, nmp, nml)
22 b = ta_cat(jb, b, "\",\"presenters\":[\"query:?cap=\",\"header:X-Nishi-Cap\",\"header:Authorization Bearer\",\"body:params._cap\"]" as *u8)
23 b = ta_cat(jb, b, "}}}" as *u8)
24 return b
25}
26func rc_one(code:i64,presented:i64,cause:*u8)->i64{
27 let out:*u8=sys_mmap(8192)
28 let start:i64=ta_cat(out,0,"{\"jsonrpc\":\"2.0\",\"id\":1")
29 let before:i64=rc_before(out,start,"nx_txtscan",10,code,presented)
30 sys_write(1,out,before);sys_write(1,"\n",1)
31 let n:i64=ta_cap_deny(out,start,"nx_txtscan",10,code,presented)
32 sys_write(1,out,n);sys_write(1,"\n",1)
33 if rc_has(out,n,cause)!=1{return 1}
34 if rc_has(out,n,"\"dispatched\":false")!=1{return 1}
35 if rc_has(out,n,"after-auth-correction")!=1{if rc_has(out,n,"after-verifier-recovery")!=1{return 1}}
36 if presented==1{if rc_has(out,n,"single-presenter")!=1{return 1}}
37 return 0
38}
39func main()->i64{
40 var fails:i64=0
41 fails=fails+rc_one(0-9,0,"capability-absent")
42 fails=fails+rc_one(CAPT_DENY_MAC,1,"signature-or-format-invalid")
43 fails=fails+rc_one(CAPT_DENY_EXP,1,"capability-expired")
44 fails=fails+rc_one(CAPT_DENY_TOOL,1,"tool-not-granted")
45 fails=fails+rc_one(CAPT_DENY_REVOKED,1,"capability-revoked")
46 fails=fails+rc_one(0-12,1,"verification-failed")
47 let sl:*i64=sys_mmap(16) as *i64;let secret:*u8=ta_load_cap_secret(sl)
48 let cap:*u8=sys_mmap(512);let cn:i64=capt_issue(secret,sl[0],"other_tool",10,sys_now_realtime_sec()+60,sys_now_realtime_sec(),cap,512)
49 if cn<=0{return 2}
50 let req:*u8=sys_mmap(2048);var rn:i64=ta_cat(req,0,"POST /mcp HTTP/1.1\r\nX-Nishi-Cap: ");rn=ta_catb(req,rn,cap,cn);rn=ta_cat(req,rn,"\r\n\r\n")
51 let body:*u8="{\"name\":\"nx_txtscan\",\"_cap\":\"invalid-first-presenter\"}"
52 let out:*u8=sys_mmap(1048576);let start:i64=ta_cat(out,0,"{\"jsonrpc\":\"2.0\",\"id\":7")
53 let n:i64=ta_mcp_call(TA_TOOLPFX,req,rn,body,ta_slen(body),out,start)
54 sys_write(1,out,n);sys_write(1,"\n",1)
55 if rc_has(out,n,"signature-or-format-invalid")!=1{fails=fails+1}
56 if rc_has(out,n,"first-presenter-failure")!=1{fails=fails+1}
57 if rc_has(out,n,"invalid-first-presenter")==1{fails=fails+1}
58 if fails==0{sys_write(1,"RECOVERY-GATE PASS 7 cases\n",27);return 0}
59 sys_write(1,"RECOVERY-GATE FAIL\n",19);return 1
60}