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}