code wiki / (root) / nx_toolreg_reap.nx

nx_toolreg_reap.nx source

↩ module page · 168 lines · 7782 B

1// nx_toolreg_reap.nx -- REMOVE named scaffold rows from tool_allowlist.conf. The counterpart the registry 2// never had: nx_toolreg_reconcile only ever ADDS (rows=830 registered=0 already=815), /api has a 3// tools/register route and NO unregister, and nx_fs_write refuses the allowlist by construction -- correctly, 4// since a tool that can EDIT the capability allowlist can GRANT ITSELF ANYTHING. So scaffold registrations 5// accumulated forever with no sanctioned way to clear them (debt 1785976684). 6// 7// WHY THIS IS SAFE TO EXIST AT ALL, and why it is a separate organ rather than a verb on the registrar: 8// this organ can ONLY REMOVE, never add and never rewrite a target. Removal is strictly DE-privileging -- 9// the worst case is a tool stops being callable, which is a recoverable annoyance, whereas an organ that 10// could add or repoint a row would be a privilege-granting oracle. Single responsibility is the security 11// property here, not a style preference. 12// 13// FAIL-CLOSED PREDICATE: a row is reapable ONLY if its elf path ends in ".new" -- the staged-artifact shape 14// that scaffold aliases have. A row pointing at a promoted ".elf" is REFUSED and reported, so a fat-fingered 15// name can never unregister a live tool. Names are EXPLICIT: there is no wildcard sweep, because rows like 16// nx_meshmerge_staged and nx_ccingest_r7 also point at .new and other seats depend on them. 17// nx_toolreg_reap <name> [<name>...] | nx_toolreg_reap --list (show reapable rows, change nothing) 18// license_tier: ORIGINAL expect_exit: 0 19import "nx_syscalls.nx" 20 21const TR_CONF: *u8 = "tool_allowlist.conf" 22const TR_TMP: *u8 = "tool_allowlist.conf.reaptmp" 23const TR_CAP: i64 = 1048576 24const TR_MODE: i64 = 0x1a4 25const TR_MAXNAME: i64 = 128 26 27func tr_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 28func tr_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 29func tr_wn(v: i64) -> i64 { 30 let b: *u8=sys_mmap(32); var x: i64=v; var i: i64=31 31 if x==0 { b[i]=48 as u8; i=i-1 } 32 while x>0 { b[i]=(48+x%10) as u8; x=x/10; i=i-1 } 33 sys_write(1, ((b as i64)+i+1) as *u8, 31-i); return 0 34} 35// does the row that starts at ls have EXACTLY this name in field 0? (exact, never a prefix: 36// nx_csgate_r1 must not match nx_csgate_r11) 37func tr_name_is(buf: *u8, ls: i64, le: i64, nm: *u8) -> i64 { 38 let n: i64 = tr_slen(nm) 39 if ls+n > le { return 0 } 40 var k: i64 = 0 41 while k<n { if buf[ls+k]!=nm[k] { return 0 } k=k+1 } 42 if ls+n == le { return 0 } // name with no fields = malformed, leave it alone 43 if buf[ls+n] != (9 as u8) { return 0 } // must be followed by TAB = end of field 0 44 return 1 45} 46// is this row's elf field a STAGED artifact (ends .new)? that is the only reapable shape. 47func tr_row_staged(buf: *u8, ls: i64, le: i64) -> i64 { 48 // field 1 runs from the first TAB to the second TAB (or end of line) 49 var t1: i64 = 0-1 50 var j: i64 = ls 51 while j<le { if buf[j]==(9 as u8) { t1=j; j=le } else { j=j+1 } } 52 if t1<0 { return 0 } 53 var t2: i64 = le 54 var k: i64 = t1+1 55 while k<le { if buf[k]==(9 as u8) { t2=k; k=le } else { k=k+1 } } 56 if t2-t1 < 5 { return 0 } 57 // compare the last 4 bytes of field 1 against ".new" 58 if buf[t2-4]!=(46 as u8) { return 0 } 59 if buf[t2-3]!=(110 as u8) { return 0 } 60 if buf[t2-2]!=(101 as u8) { return 0 } 61 if buf[t2-1]!=(119 as u8) { return 0 } 62 return 1 63} 64func tr_emit_field1(buf: *u8, ls: i64, le: i64) -> i64 { 65 var t1: i64 = 0-1 66 var j: i64 = ls 67 while j<le { if buf[j]==(9 as u8) { t1=j; j=le } else { j=j+1 } } 68 if t1<0 { return 0 } 69 var t2: i64 = le 70 var k: i64 = t1+1 71 while k<le { if buf[k]==(9 as u8) { t2=k; k=le } else { k=k+1 } } 72 sys_write(1, ((buf as i64)+t1+1) as *u8, t2-t1-1) 73 return 0 74} 75 76func main(argc: i64, argv: *i64) -> i64 { 77 if argc < 2 { 78 tr_w("usage: nx_toolreg_reap <name> [<name>...] | --list\n" as *u8) 79 tr_w(" removes named rows from tool_allowlist.conf. ONLY rows whose elf ends .new are reapable;\n" as *u8) 80 tr_w(" a row pointing at a promoted .elf is REFUSED so a live tool can never be unregistered.\n" as *u8) 81 return 0 82 } 83 let buf: *u8 = sys_mmap(TR_CAP) 84 let fd: i64 = sys_openat_rd(TR_CONF) 85 if fd < 0 { tr_w("REAP-FAIL cannot read tool_allowlist.conf\n" as *u8); sys_exit(1); return 1 } 86 var n: i64 = 0 87 var go: i64 = 1 88 while go==1 { 89 let r: i64 = sys_read(fd, ((buf as i64)+n) as *u8, TR_CAP-n) 90 if r<=0 { go=0 } else { n=n+r } 91 if n>=TR_CAP { go=0 } 92 } 93 sys_close(fd) 94 if n<=0 { tr_w("REAP-FAIL empty allowlist -- refusing to write\n" as *u8); sys_exit(1); return 1 } 95 96 var listonly: i64 = 0 97 let a1: *u8 = argv[1] as *u8 98 if a1[0]==(45 as u8) { listonly = 1 } 99 100 let outb: *u8 = sys_mmap(TR_CAP) 101 var o: i64 = 0 102 var rows: i64 = 0 103 var reaped: i64 = 0 104 var refused: i64 = 0 105 var i: i64 = 0 106 while i<n { 107 let ls: i64 = i 108 var le: i64 = ls 109 var s: i64 = 1 110 while s==1 { if le>=n { s=0 } else { if buf[le]==(10 as u8) { s=0 } else { le=le+1 } } } 111 i = le+1 112 var drop: i64 = 0 113 if le>ls { 114 rows = rows + 1 115 if listonly==1 { 116 if tr_row_staged(buf, ls, le)==1 { 117 tr_w(" reapable " as *u8); sys_write(1, ((buf as i64)+ls) as *u8, le-ls); tr_w("\n" as *u8) 118 } 119 } else { 120 var ai: i64 = 1 121 while ai<argc { 122 let want: *u8 = argv[ai] as *u8 123 if tr_name_is(buf, ls, le, want)==1 { 124 if tr_row_staged(buf, ls, le)==1 { 125 drop = 1 126 reaped = reaped + 1 127 tr_w(" REAPED " as *u8); tr_w(want); tr_w(" -> " as *u8); tr_emit_field1(buf, ls, le); tr_w("\n" as *u8) 128 } else { 129 refused = refused + 1 130 tr_w(" REFUSED " as *u8); tr_w(want) 131 tr_w(" -- elf is NOT a staged .new artifact (" as *u8); tr_emit_field1(buf, ls, le) 132 tr_w("); a promoted tool is never unregistered by this organ\n" as *u8) 133 } 134 ai = argc 135 } else { ai = ai + 1 } 136 } 137 } 138 } 139 if drop==0 { 140 var c: i64 = ls 141 while c<le { outb[o]=buf[c]; o=o+1; c=c+1 } 142 if le<n { outb[o]=10 as u8; o=o+1 } 143 } 144 } 145 if listonly==1 { 146 tr_w("NX-TOOLREG-REAP --list rows=" as *u8); tr_wn(rows); tr_w(" (nothing written)\n" as *u8) 147 return 0 148 } 149 if reaped==0 { 150 tr_w("NX-TOOLREG-REAP rows=" as *u8); tr_wn(rows) 151 tr_w(" reaped=0 refused=" as *u8); tr_wn(refused) 152 tr_w(" -- NOTHING WRITTEN (a no-op must not rewrite the file other seats are reading)\n" as *u8) 153 return 0 154 } 155 // atomic install: write the tmp in full, then rename over the live conf. A partial write can never be 156 // observed as the allowlist, so a crash mid-reap cannot leave the estate with an unreadable registry. 157 let wfd: i64 = sys_openat_wr(TR_TMP, TR_MODE) 158 if wfd < 0 { tr_w("REAP-FAIL cannot open tmp -- LIVE CONF UNTOUCHED\n" as *u8); sys_exit(1); return 1 } 159 sys_write(wfd, outb, o) 160 sys_close(wfd) 161 if sys_renameat(TR_TMP, TR_CONF) < 0 { tr_w("REAP-FAIL rename -- LIVE CONF UNTOUCHED\n" as *u8); sys_exit(1); return 1 } 162 tr_w("NX-TOOLREG-REAP rows_in=" as *u8); tr_wn(rows) 163 tr_w(" reaped=" as *u8); tr_wn(reaped) 164 tr_w(" refused=" as *u8); tr_wn(refused) 165 tr_w(" bytes_out=" as *u8); tr_wn(o) 166 tr_w("\n" as *u8) 167 return 0 168}