code wiki / _hdl_build / nx_deploy_ready.nx
nx_deploy_ready.nx source
↩ module page · 145 lines · 8583 B
1// nx_deploy_ready.nx -- PRE-DEPLOY SAFETY GATE (operator: "prevent things like this... deploy... managed").
2// The capstone of the deploy-reliability trilogy: an agent/session calls this BEFORE deploying an organ to
3// learn if it is SAFE. Aggregates the supervised signals into ONE actionable verdict instead of 3 separate
4// checks -- proactive prevention (won't deploy into a drifted buildroot or after a contract regression).
5// Data-driven (rule 11): knowledge/registry/deploy_checks.tsv rows = name<TAB>file<TAB>marker<TAB>severity<TAB>remediation.
6// A check PASSES if <file> contains <marker>. severity BLOCK -> a fail makes deploy UNSAFE; WARN -> advisory.
7// nx_deploy_ready check [manifest] (JSON: deploy_safe + per-check pass/severity + blockers + remediations)
8// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
9import "nx_syscalls.nx"
10
11const DR_CAP: i64 = 262144
12const DR_TAB: i64 = 9
13const DR_NL: i64 = 10
14const DR_HASH: i64 = 35
15const DR_STDERR: i64 = 2
16const DR_SPAN: i64 = 16
17const DR_EXIT_USAGE: i64 = 2
18
19func dr_werr(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(DR_STDERR, s, n); return 0 }
20func dr_vlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
21func dr_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { d[o] = s[i]; o = o + 1; i = i + 1 } return o }
22func dr_catn(d: *u8, o: i64, v: i64) -> i64 { let t: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 } var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 } while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } var i: i64 = 0; while i < k { d[o] = t[k-1-i]; o = o + 1; i = i + 1 } return o }
23func dr_cat_esc(d: *u8, o: i64, q: *u8, s: i64, e: i64) -> i64 { var i: i64 = s; while i < e { var c: i64 = q[i] as i64; if c == 34 { c = 39 } if c == 92 { c = 47 } if c < 32 { c = 32 } d[o] = c as u8; o = o + 1; i = i + 1 } return o }
24func dr_read(path: *u8, buf: *u8, cap: i64) -> i64 {
25 let fd: i64 = sys_openat_rd(path)
26 if fd < 0 { return 0 - 1 }
27 var n: i64 = 0
28 var go: i64 = 1
29 while go == 1 { let r: i64 = sys_read(fd, ((buf as i64) + n) as *u8, cap - n); if r <= 0 { go = 0 } else { n = n + r } if n >= cap { go = 0 } }
30 sys_close(fd)
31 return n
32}
33func dr_contains(buf: *u8, n: i64, lit: *u8) -> i64 {
34 var ll: i64 = 0
35 while lit[ll] != (0 as u8) { ll = ll + 1 }
36 if ll == 0 { return 1 }
37 var i: i64 = 0
38 while i + ll <= n {
39 var j: i64 = 0
40 var ok: i64 = 1
41 while j < ll { if buf[i+j] != lit[j] { ok = 0; j = ll } else { j = j + 1 } }
42 if ok == 1 { return 1 }
43 i = i + 1
44 }
45 return 0
46}
47func dr_le(q: *u8, i: i64, n: i64) -> i64 { var e: i64 = i; var s: i64 = 1; while s == 1 { if e >= n { s = 0 } else { if q[e] == (DR_NL as u8) { s = 0 } else { e = e + 1 } } } return e }
48func dr_col(q: *u8, ls: i64, le: i64, c: i64, out: *i64) -> i64 {
49 var col: i64 = 0
50 var p: i64 = ls
51 while col < c {
52 var s: i64 = 1
53 while s == 1 { if p >= le { return 0 } if q[p] == (DR_TAB as u8) { s = 0 } else { p = p + 1 } }
54 p = p + 1
55 col = col + 1
56 }
57 var e: i64 = p
58 var s2: i64 = 1
59 while s2 == 1 { if e >= le { s2 = 0 } else { if q[e] == (DR_TAB as u8) { s2 = 0 } else { e = e + 1 } } }
60 out[0] = p
61 out[1] = e
62 return 1
63}
64func dr_cstr(q: *u8, s: i64, e: i64, dst: *u8) -> i64 { var i: i64 = 0; while s + i < e { dst[i] = q[s+i]; i = i + 1 } dst[i] = 0 as u8; return i }
65func dr_span_is(q: *u8, s: i64, e: i64, lit: *u8) -> i64 { var i: i64 = 0; while s + i < e { if lit[i] == (0 as u8) { return 0 } if q[s+i] != lit[i] { return 0 } i = i + 1 } if lit[i] != (0 as u8) { return 0 } return 1 }
66func main(argc: i64, argv: *i64) -> i64 {
67 var verb: *u8 = "check" as *u8
68 if argc > 1 { verb = argv[1] as *u8 }
69 if dr_contains(verb, dr_vlen(verb), "check" as *u8) == 0 { dr_werr("usage: nx_deploy_ready check [manifest]\n" as *u8); sys_exit(DR_EXIT_USAGE); return DR_EXIT_USAGE }
70 var mpath: *u8 = "knowledge/registry/deploy_checks.tsv" as *u8
71 if argc > 2 { mpath = argv[2] as *u8 }
72 let man: *u8 = sys_mmap(DR_CAP)
73 let mn: i64 = dr_read(mpath, man, DR_CAP)
74 if mn <= 0 { dr_werr("DR-FAIL manifest empty or unreadable\n" as *u8); sys_exit(1); return 1 }
75 let fbuf: *u8 = sys_mmap(DR_CAP)
76 let fpath: *u8 = sys_mmap(512)
77 let mark: *u8 = sys_mmap(512)
78 let c0: *i64 = sys_mmap(DR_SPAN) as *i64
79 let c1: *i64 = sys_mmap(DR_SPAN) as *i64
80 let c2: *i64 = sys_mmap(DR_SPAN) as *i64
81 let c3: *i64 = sys_mmap(DR_SPAN) as *i64
82 let c4: *i64 = sys_mmap(DR_SPAN) as *i64
83 let out: *u8 = sys_mmap(DR_CAP)
84 var o: i64 = 0
85 o = dr_cat(out, o, "{\"verb\":\"check\",\"checks\":[" as *u8)
86 var total: i64 = 0
87 var blockers: i64 = 0
88 var warns: i64 = 0
89 var emitted: i64 = 0
90 var i: i64 = 0
91 while i < mn {
92 let le: i64 = dr_le(man, i, mn)
93 if le > i { if (man[i] as i64) != DR_HASH {
94 if dr_col(man, i, le, 0, c0) == 1 { if dr_col(man, i, le, 1, c1) == 1 { if dr_col(man, i, le, 2, c2) == 1 { if dr_col(man, i, le, 3, c3) == 1 {
95 dr_cstr(man, c1[0], c1[1], fpath)
96 dr_cstr(man, c2[0], c2[1], mark)
97 total = total + 1
98 let fn: i64 = dr_read(fpath, fbuf, DR_CAP)
99 var pass: i64 = 0
100 if fn > 0 { if dr_contains(fbuf, fn, mark) == 1 { pass = 1 } }
101 var is_block: i64 = 0
102 if dr_span_is(man, c3[0], c3[1], "BLOCK" as *u8) == 1 { is_block = 1 }
103 if pass == 0 { if is_block == 1 { blockers = blockers + 1 } else { warns = warns + 1 } }
104 if emitted > 0 { o = dr_cat(out, o, "," as *u8) }
105 o = dr_cat(out, o, "{\"name\":\"" as *u8)
106 o = dr_cat_esc(out, o, man, c0[0], c0[1])
107 o = dr_cat(out, o, "\",\"pass\":" as *u8)
108 o = dr_catn(out, o, pass)
109 o = dr_cat(out, o, ",\"severity\":\"" as *u8)
110 o = dr_cat_esc(out, o, man, c3[0], c3[1])
111 o = dr_cat(out, o, "\"" as *u8)
112 if pass == 0 { if dr_col(man, i, le, 4, c4) == 1 { o = dr_cat(out, o, ",\"remediation\":\"" as *u8); o = dr_cat_esc(out, o, man, c4[0], c4[1]); o = dr_cat(out, o, "\"" as *u8) } }
113 o = dr_cat(out, o, "}" as *u8)
114 emitted = emitted + 1
115 } } } }
116 } }
117 i = le + 1
118 }
119 o = dr_cat(out, o, "],\"total\":" as *u8)
120 o = dr_catn(out, o, total)
121 o = dr_cat(out, o, ",\"blockers\":" as *u8)
122 o = dr_catn(out, o, blockers)
123 o = dr_cat(out, o, ",\"warnings\":" as *u8)
124 o = dr_catn(out, o, warns)
125 o = dr_cat(out, o, ",\"deploy_safe\":" as *u8)
126 if blockers == 0 { o = dr_cat(out, o, "true" as *u8) } else { o = dr_cat(out, o, "false" as *u8) }
127 o = dr_cat(out, o, ",\"verdict\":\"" as *u8)
128 if blockers > 0 { o = dr_cat(out, o, "DEPLOY-BLOCKED" as *u8) } else { if warns > 0 { o = dr_cat(out, o, "DEPLOY-SAFE-WITH-WARNINGS" as *u8) } else { o = dr_cat(out, o, "DEPLOY-SAFE" as *u8) } }
129 o = dr_cat(out, o, "\",\"envelope\":\"manifest knowledge/registry/deploy_checks.tsv + each evidence file read bounded per DR_CAP; a check whose evidence file exceeds the cap reads TRUNCATED and its marker may be missed -- declared per the scale-law (F846), never silent\"}\n" as *u8)
130 sys_write(1, out, o)
131 // ---- EXIT CODE NOW CARRIES THE VERDICT (2026-07-30) ------------------------------------------------
132 // This was sys_exit(0) UNCONDITIONALLY -- even when the verdict is DEPLOY-BLOCKED. So `nx_deploy_ready
133 // check && deploy` sailed straight through a blocking verdict, and NO caller checking $? could ever act
134 // on this gate. A gate whose exit code is constant cannot gate anything; it can only be read by something
135 // that already knows to parse its JSON. 0 = safe, 3 = DEPLOY-BLOCKED.
136 // WARNINGS DELIBERATELY STILL EXIT 0: warnings here are evidence DEBT, not a stop. A gate that exits
137 // nonzero on every warning gets wrapped in `|| true` and then protects nothing -- this file's own
138 // manifest makes that argument, and it is right.
139 // BLAST RADIUS MEASURED, NOT ASSUMED: grep across 19951 files found exactly ONE in-tree caller of
140 // nx_deploy_ready.elf (md_exec_deploy_ready), and it ignores the exit code and parses the JSON. So no
141 // existing in-tree behaviour changes; this only stops the gate from lying to future callers.
142 if blockers > 0 { sys_exit(3); return 3 }
143 sys_exit(0)
144 return 0
145}