nx_mcp_authenticated_gate.nx source
↩ module page · 76 lines · 4930 B
1// Fresh native stdio read-only authenticated roundtrip using existing HTTPS fixture.
2// Arguments are executable, base URL, existing capability FILE, expected source bytes.
3// Capability bytes are never printed or copied by this gate.
4import "nx_mcp_https_gate.nx"
5import "nx_cap_mint.nx"
6
7func mag_reply_cap(input:*u8,output:*u8,expected_exp:i64,expected_nonce:i64)->i64 {
8 var file:NxCapFile
9 if cm_file_read(input,&file)!=0{return -1}
10 var parsed:i64=0
11 let v:*NxValue=nx_value_parse_json(file.bytes,file.length,&parsed)
12 if parsed!=NX_VAL_PARSE_OK||v.kind!=NX_VAL_OBJECT{cm_file_close(&file);return -2}
13 var i:i64=0
14 while i<v.n_items{
15 var j:i64=0;while j<i{
16 if nx_value_bytes_equal(v.keys_ptr[i],v.key_lens_ptr[i],v.keys_ptr[j],v.key_lens_ptr[j])==1{cm_file_close(&file);return -2};j=j+1
17 };i=i+1
18 }
19 let action:*NxValue=nx_value_object_get(v,"action",6)
20 let allow:*NxValue=nx_value_object_get(v,"allow",5)
21 let token:*NxValue=nx_value_object_get(v,"cap",3)
22 var exp:i64=0;var nonce:i64=0
23 if action==(0 as *NxValue)||allow==(0 as *NxValue)||token==(0 as *NxValue){cm_file_close(&file);return -2}
24 if action.kind!=NX_VAL_STRING||allow.kind!=NX_VAL_STRING||token.kind!=NX_VAL_STRING{cm_file_close(&file);return -2}
25 if nx_value_bytes_equal(action.str_ptr,action.str_len,"MINTED",6)!=1||nx_value_bytes_equal(allow.str_ptr,allow.str_len,"nx_fs",5)!=1{cm_file_close(&file);return -2}
26 if nx_value_object_get_int(v,"exp",3,&exp)!=1||nx_value_object_get_int(v,"nonce",5,&nonce)!=1{cm_file_close(&file);return -2}
27 if exp!=expected_exp||nonce!=expected_nonce||exp<=sys_now_realtime_sec(){cm_file_close(&file);return -3}
28 let capacity:i64=capt_issue_capacity(5,exp,nonce)
29 let payload:*u8=sys_mmap_try(capacity);if payload==(0 as *u8){cm_file_close(&file);return -4}
30 let pn:i64=capt_payload("nx_fs",5,exp,nonce,payload)
31 var valid:i64=token.str_len==capacity&&token.str_ptr[pn]==46 as u8
32 if valid!=0{valid=nx_value_bytes_equal(token.str_ptr,pn,payload,pn)}
33 sys_munmap_direct(payload,capacity)
34 if valid!=1{cm_file_close(&file);return -3}
35 let fd:i64=sys_openat_exclusive(output,MODE_0600)
36 if fd<0{cm_file_close(&file);return -4}
37 var wr:NxFileWriteResult
38 let rc:i64=fio_write_sync_fd(fd,token.str_ptr,token.str_len,&wr)
39 i=0;while i<token.str_len{token.str_ptr[i]=0 as u8;i=i+1}
40 if cm_file_close(&file)!=0{return -4}
41 if rc!=0{return -4}
42 gv_puts("scoped_capability=nx_fs; token_bytes_hidden=1\n")
43 gv_kv("cap_expiry",exp);gv_kv("cap_nonce",nonce)
44 return 0
45}
46
47func main(argc:i64,argv:*i64)->i64 {
48 if argc!=5&&argc!=8{return 2}
49 let c:*i64=gv_ctr()
50 let prefix:*u8=sys_mmap(256);var pos:i64=mpe_cat(prefix,0,"/tmp/nishi-mcp-auth-gate-")
51 pos=mpe_catn(prefix,pos,sys_now_ms());prefix[pos]=0 as u8
52 var credential:*u8=argv[3] as *u8
53 if argc==8{
54 if mr_equal(argv[5] as *u8,mr_len(argv[5] as *u8),"--mint-response")!=1{return 2}
55 credential=mhg_path(prefix,".scoped.cap")
56 let extract:i64=mag_reply_cap(argv[3] as *u8,credential,cm_atoi(argv[6] as *u8),cm_atoi(argv[7] as *u8))
57 if extract!=0{gv_kv("private_capability_handoff_error",extract);return 3}
58 }
59 let negative_cap:*u8=mhg_path(prefix,".noncredential")
60 if mhg_file(negative_cap,"nishi-negative-control-not-a-capability\n")!=0{return 2}
61 let request:*u8="{\"jsonrpc\":\"2.0\",\"id\":\"auth-size-a\",\"method\":\"tools/call\",\"params\":{\"name\":\"nx_fs\",\"arguments\":{\"argv\":[\"size\",\"buildroot/runtime/nx_mcp_stdio.nx\"]}}}\n{\"jsonrpc\":\"2.0\",\"id\":\"auth-size-b\",\"method\":\"tools/call\",\"params\":{\"name\":\"nx_fs\",\"arguments\":{\"argv\":[\"size\",\"buildroot/runtime/nx_mcp_stdio.nx\"]}}}\n"
62 let b:*u8=sys_mmap(16384);var n:i64=0
63 let bad_rc:i64=mhg_run(argv[1] as *u8,argv[2] as *u8,mhg_path(prefix,".negative"),negative_cap,request,b,&n)
64 gv_check("noncredential-process-survives",bad_rc==0,c)
65 gv_check("noncredential-does-not-read-source",mhg_lines(b,n)==2&&mhg_has(b,n,"NX-FS-SIZE")==0,c)
66 let good_rc:i64=mhg_run(argv[1] as *u8,argv[2] as *u8,mhg_path(prefix,".authenticated"),credential,request,b,&n)
67 let expected:*u8=sys_mmap(mpe_slen(argv[4] as *u8)+mpe_slen("bytes= exact=1")+1)
68 var at:i64=mpe_cat(expected,0,"bytes=");at=mpe_cat(expected,at,argv[4] as *u8);at=mpe_cat(expected,at," exact=1");expected[at]=0 as u8
69 gv_check("authenticated-process-survives",good_rc==0,c)
70 gv_check("two-complete-correlated-responses",mhg_lines(b,n)==2&&mhg_has(b,n,"\"id\":\"auth-size-a\"")==1&&mhg_has(b,n,"\"id\":\"auth-size-b\"")==1,c)
71 gv_check("actual-source-size-matches",mhg_has(b,n,"NX-FS-SIZE buildroot/runtime/nx_mcp_stdio.nx")==1&&mhg_has(b,n,expected)==1,c)
72 gv_check("no-authenticated-errors",mhg_has(b,n,"\"error\"")==0&&mhg_has(b,n,"\"isError\":true")==0,c)
73 gv_kv("authenticated_response_bytes",n)
74 gv_puts("retained_prefix=");gv_puts(prefix);gv_puts("\n")
75 return gv_verdict("MCP-AUTHENTICATED",c,"Read-only tools/call through fresh exact executable; invalid-capability negative control; capability file stays private.")
76}