code wiki / (root) / nx_tools_api_recovery_comparison_gate_v3_t316.nx

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}