code wiki / (root) / nx_toolreg_reap.nx

nx_toolreg_reap.nx source

↩ module page · 262 lines · 12681 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// 19// ---- THE SUPERSEDED LANE (2026-08-15) --------------------------------------------------------------- 20// nx_toolreg_reap --superseded <name> <superseded-by> 21// WHY IT WAS ADDED: a rename can leave a PROMOTED duplicate registered (measured: nx_promotestale and 22// nx_servedrift, both superseded by nx_artifactdrift, three registry rows for one capability). The add 23// lane exists (/api/tools/register, nx_toolreg_reconcile), the scaffold-reap lane exists, and there was 24// NO sovereign path to unregister a promoted duplicate -- so duplicates could only accumulate. 25// WHY IT DOES NOT WEAKEN THE DEFAULT: the bare-name lane still refuses every promoted row, unchanged. 26// This lane is opt-in, takes exactly ONE name, has no wildcard, and REFUSES unless the caller also names 27// a DIFFERENT row that is present AND promoted -- so the capability is proven to still have a home. The 28// original property survives: a fat-fingered single name can never unregister a live tool, because one 29// name is no longer enough. And removal stays strictly de-privileging, which is this organ's whole 30// security argument. 31// ⚠THE CEILING, STATED WITH THE REMEDY: this proves a promoted alternative EXISTS, never that it is 32// semantically equivalent. That last step is the caller's judgement and the organ says so rather than 33// implying it checked. ★★★★★A GUARD THAT CANNOT VERIFY THE CLAIM IT GATES MUST NAME WHAT IT DID VERIFY, 34// OR THE NEXT READER CREDITS IT WITH THE STRONGER CHECK. 35// license_tier: ORIGINAL expect_exit: 0 36import "nx_syscalls.nx" 37 38const TR_CONF: *u8 = "tool_allowlist.conf" 39const TR_TMP: *u8 = "tool_allowlist.conf.reaptmp" 40const TR_CAP: i64 = 1048576 41const TR_MODE: i64 = 0x1a4 42const TR_MAXNAME: i64 = 128 43 44func 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 } 45func tr_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 46func tr_wn(v: i64) -> i64 { 47 let b: *u8=sys_mmap(32); var x: i64=v; var i: i64=31 48 if x==0 { b[i]=48 as u8; i=i-1 } 49 while x>0 { b[i]=(48+x%10) as u8; x=x/10; i=i-1 } 50 sys_write(1, ((b as i64)+i+1) as *u8, 31-i); return 0 51} 52// does the row that starts at ls have EXACTLY this name in field 0? (exact, never a prefix: 53// nx_csgate_r1 must not match nx_csgate_r11) 54func tr_name_is(buf: *u8, ls: i64, le: i64, nm: *u8) -> i64 { 55 let n: i64 = tr_slen(nm) 56 if ls+n > le { return 0 } 57 var k: i64 = 0 58 while k<n { if buf[ls+k]!=nm[k] { return 0 } k=k+1 } 59 if ls+n == le { return 0 } // name with no fields = malformed, leave it alone 60 if buf[ls+n] != (9 as u8) { return 0 } // must be followed by TAB = end of field 0 61 return 1 62} 63// is this row's elf field a STAGED artifact (ends .new)? that is the only reapable shape. 64func tr_row_staged(buf: *u8, ls: i64, le: i64) -> i64 { 65 // field 1 runs from the first TAB to the second TAB (or end of line) 66 var t1: i64 = 0-1 67 var j: i64 = ls 68 while j<le { if buf[j]==(9 as u8) { t1=j; j=le } else { j=j+1 } } 69 if t1<0 { return 0 } 70 var t2: i64 = le 71 var k: i64 = t1+1 72 while k<le { if buf[k]==(9 as u8) { t2=k; k=le } else { k=k+1 } } 73 if t2-t1 < 5 { return 0 } 74 // compare the last 4 bytes of field 1 against ".new" 75 if buf[t2-4]!=(46 as u8) { return 0 } 76 if buf[t2-3]!=(110 as u8) { return 0 } 77 if buf[t2-2]!=(101 as u8) { return 0 } 78 if buf[t2-1]!=(119 as u8) { return 0 } 79 return 1 80} 81func tr_emit_field1(buf: *u8, ls: i64, le: i64) -> i64 { 82 var t1: i64 = 0-1 83 var j: i64 = ls 84 while j<le { if buf[j]==(9 as u8) { t1=j; j=le } else { j=j+1 } } 85 if t1<0 { return 0 } 86 var t2: i64 = le 87 var k: i64 = t1+1 88 while k<le { if buf[k]==(9 as u8) { t2=k; k=le } else { k=k+1 } } 89 sys_write(1, ((buf as i64)+t1+1) as *u8, t2-t1-1) 90 return 0 91} 92func tr_eq(a: *u8, b: *u8) -> i64 { 93 let la: i64 = tr_slen(a) 94 let lb: i64 = tr_slen(b) 95 if la != lb { return 0 } 96 var i: i64 = 0 97 while i < la { if a[i] != b[i] { return 0 } i = i + 1 } 98 return 1 99} 100// 0 = no such row | 1 = present and STAGED (.new) | 2 = present and PROMOTED 101// ★THREE STATES, NOT TWO: "absent" and "present but staged" are different refusals for the survivor 102// argument below, and collapsing them would report a typo'd name as a policy violation. 103func tr_find(buf: *u8, n: i64, nm: *u8) -> i64 { 104 var i: i64 = 0 105 while i < n { 106 let ls: i64 = i 107 var le: i64 = ls 108 var s: i64 = 1 109 while s == 1 { if le >= n { s = 0 } else { if buf[le] == (10 as u8) { s = 0 } else { le = le + 1 } } } 110 i = le + 1 111 if le > ls { 112 if tr_name_is(buf, ls, le, nm) == 1 { 113 if tr_row_staged(buf, ls, le) == 1 { return 1 } 114 return 2 115 } 116 } 117 } 118 return 0 119} 120 121func main(argc: i64, argv: *i64) -> i64 { 122 if argc < 2 { 123 tr_w("usage: nx_toolreg_reap <name> [<name>...] | --list | --superseded <name> <superseded-by>\n" as *u8) 124 tr_w(" removes named rows from tool_allowlist.conf. ONLY rows whose elf ends .new are reapable;\n" as *u8) 125 tr_w(" a row pointing at a promoted .elf is REFUSED so a live tool can never be unregistered.\n" as *u8) 126 tr_w(" --superseded removes ONE promoted row, and only when a DIFFERENT promoted row is named as\n" as *u8) 127 tr_w(" the surviving home of the capability -- for duplicates left behind by a rename.\n" as *u8) 128 return 0 129 } 130 let buf: *u8 = sys_mmap(TR_CAP) 131 let fd: i64 = sys_openat_rd(TR_CONF) 132 if fd < 0 { tr_w("REAP-FAIL cannot read tool_allowlist.conf\n" as *u8); sys_exit(1); return 1 } 133 var n: i64 = 0 134 var go: i64 = 1 135 while go==1 { 136 let r: i64 = sys_read(fd, ((buf as i64)+n) as *u8, TR_CAP-n) 137 if r<=0 { go=0 } else { n=n+r } 138 if n>=TR_CAP { go=0 } 139 } 140 sys_close(fd) 141 if n<=0 { tr_w("REAP-FAIL empty allowlist -- refusing to write\n" as *u8); sys_exit(1); return 1 } 142 143 var listonly: i64 = 0 144 var supmode: i64 = 0 145 var supname: *u8 = 0 as *u8 146 var supby: *u8 = 0 as *u8 147 let a1: *u8 = argv[1] as *u8 148 if tr_eq(a1, "--superseded" as *u8) == 1 { supmode = 1 } else { 149 if a1[0]==(45 as u8) { listonly = 1 } 150 } 151 if supmode == 1 { 152 if argc < 4 { 153 tr_w("usage: nx_toolreg_reap --superseded <name> <superseded-by>\n" as *u8) 154 tr_w(" removes ONE promoted row, and only when a DIFFERENT promoted row is named as the\n" as *u8) 155 tr_w(" surviving home of the capability. Both names must already be in the registry.\n" as *u8) 156 sys_exit(2); return 2 157 } 158 supname = argv[2] as *u8 159 supby = argv[3] as *u8 160 if tr_eq(supname, supby) == 1 { 161 tr_w("REAP-REFUSED -- a row cannot supersede itself; name the OTHER tool that keeps the capability\n" as *u8) 162 sys_exit(1); return 1 163 } 164 let fs: i64 = tr_find(buf, n, supname) 165 if fs == 0 { 166 tr_w("REAP-REFUSED -- no such row: " as *u8); tr_w(supname) 167 tr_w(" (nothing removed; a typo must never silently match a neighbour)\n" as *u8) 168 sys_exit(1); return 1 169 } 170 let fb: i64 = tr_find(buf, n, supby) 171 if fb == 0 { 172 tr_w("REAP-REFUSED -- the named survivor is not registered: " as *u8); tr_w(supby) 173 tr_w(" -- removing " as *u8); tr_w(supname) 174 tr_w(" would delete the capability, not relocate it\n" as *u8) 175 sys_exit(1); return 1 176 } 177 if fb == 1 { 178 tr_w("REAP-REFUSED -- the named survivor " as *u8); tr_w(supby) 179 tr_w(" is itself a STAGED .new row, which promotion deletes; it cannot be the durable home\n" as *u8) 180 sys_exit(1); return 1 181 } 182 } 183 184 let outb: *u8 = sys_mmap(TR_CAP) 185 var o: i64 = 0 186 var rows: i64 = 0 187 var reaped: i64 = 0 188 var refused: i64 = 0 189 var i: i64 = 0 190 while i<n { 191 let ls: i64 = i 192 var le: i64 = ls 193 var s: i64 = 1 194 while s==1 { if le>=n { s=0 } else { if buf[le]==(10 as u8) { s=0 } else { le=le+1 } } } 195 i = le+1 196 var drop: i64 = 0 197 if le>ls { 198 rows = rows + 1 199 if listonly==1 { 200 if tr_row_staged(buf, ls, le)==1 { 201 tr_w(" reapable " as *u8); sys_write(1, ((buf as i64)+ls) as *u8, le-ls); tr_w("\n" as *u8) 202 } 203 } else { 204 if supmode==1 { 205 if tr_name_is(buf, ls, le, supname)==1 { 206 drop = 1 207 reaped = reaped + 1 208 tr_w(" REAPED-SUPERSEDED " as *u8); tr_w(supname) 209 tr_w(" -> " as *u8); tr_emit_field1(buf, ls, le) 210 tr_w(" (capability remains registered as " as *u8); tr_w(supby); tr_w(")\n" as *u8) 211 } 212 } else { 213 var ai: i64 = 1 214 while ai<argc { 215 let want: *u8 = argv[ai] as *u8 216 if tr_name_is(buf, ls, le, want)==1 { 217 if tr_row_staged(buf, ls, le)==1 { 218 drop = 1 219 reaped = reaped + 1 220 tr_w(" REAPED " as *u8); tr_w(want); tr_w(" -> " as *u8); tr_emit_field1(buf, ls, le); tr_w("\n" as *u8) 221 } else { 222 refused = refused + 1 223 tr_w(" REFUSED " as *u8); tr_w(want) 224 tr_w(" -- elf is NOT a staged .new artifact (" as *u8); tr_emit_field1(buf, ls, le) 225 tr_w("); a promoted tool is never unregistered by this organ\n" as *u8) 226 } 227 ai = argc 228 } else { ai = ai + 1 } 229 } 230 } 231 } 232 } 233 if drop==0 { 234 var c: i64 = ls 235 while c<le { outb[o]=buf[c]; o=o+1; c=c+1 } 236 if le<n { outb[o]=10 as u8; o=o+1 } 237 } 238 } 239 if listonly==1 { 240 tr_w("NX-TOOLREG-REAP --list rows=" as *u8); tr_wn(rows); tr_w(" (nothing written)\n" as *u8) 241 return 0 242 } 243 if reaped==0 { 244 tr_w("NX-TOOLREG-REAP rows=" as *u8); tr_wn(rows) 245 tr_w(" reaped=0 refused=" as *u8); tr_wn(refused) 246 tr_w(" -- NOTHING WRITTEN (a no-op must not rewrite the file other seats are reading)\n" as *u8) 247 return 0 248 } 249 // atomic install: write the tmp in full, then rename over the live conf. A partial write can never be 250 // observed as the allowlist, so a crash mid-reap cannot leave the estate with an unreadable registry. 251 let wfd: i64 = sys_openat_wr(TR_TMP, TR_MODE) 252 if wfd < 0 { tr_w("REAP-FAIL cannot open tmp -- LIVE CONF UNTOUCHED\n" as *u8); sys_exit(1); return 1 } 253 sys_write(wfd, outb, o) 254 sys_close(wfd) 255 if sys_renameat(TR_TMP, TR_CONF) < 0 { tr_w("REAP-FAIL rename -- LIVE CONF UNTOUCHED\n" as *u8); sys_exit(1); return 1 } 256 tr_w("NX-TOOLREG-REAP rows_in=" as *u8); tr_wn(rows) 257 tr_w(" reaped=" as *u8); tr_wn(reaped) 258 tr_w(" refused=" as *u8); tr_wn(refused) 259 tr_w(" bytes_out=" as *u8); tr_wn(o) 260 tr_w("\n" as *u8) 261 return 0 262}