code wiki / _hdl_build / nx_sitegen_llm_gate.nx
nx_sitegen_llm_gate.nx source
↩ module page · 145 lines · 9352 B
1// nx_sitegen_llm_gate.nx -- the AI-OPTIONAL / GOVERNED-MODEL-SEAM gate. The contract: a local LLM (or any
2// model) may PROPOSE a site only as a `.site` blueprint (data); the sovereign parser+engine treat that output
3// as UNTRUSTED input and either build it safely or refuse it safely. The model is NEVER trusted, NEVER in the
4// build or serve path, and CANNOT (a) change the deterministic output by its formatting, (b) inject script,
5// (c) ship a non-UX-compliant page, (d) crash/smuggle via hallucinated block kinds, or (e) smuggle raw markup
6// through a text field. This proves "using AI" is exactly as safe + sovereign as "without AI" -- AI is
7// optional, only a proposer of data. No new engine: reuses nx_sitegen_parse + nx_sitegen (the governance is
8// already in them; this gate proves it for model-emitted, incl. adversarial, blueprints). Appends "CMSGATE
9// row=nx_sitegen_llm site-builder-ai-seam ... verdict=PASS" to knowledge/status/cms_gate.log on all-pass.
10// Exit 0 iff all pass. license_tier: ORIGINAL
11import "nx_sitegen_parse.nx"
12import "nx_sitegen.nx"
13import "nx_syscalls.nx"
14
15func lw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
16func lnum(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m}; let t: *u8=sys_mmap(28); 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{bb[i]=t[k-1-i];i=i+1}; sys_write(1,bb,k); return 0 }
17func lcat(dst: *u8, off: i64, s: *u8) -> i64 { var o: i64=off; var k: i64=0; while s[k]!=(0 as u8){dst[o]=s[k];o=o+1;k=k+1} return o }
18func lcatnum(dst: *u8, off: i64, v: i64) -> i64 { var o: i64=off; let t: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m}; 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{dst[o]=t[k-1-i];o=o+1;i=i+1} return o }
19
20func lrow(id: i64, ok: i64, what: *u8) -> i64 {
21 lw("LLMROW " as *u8); lnum(id); lw(" " as *u8)
22 if ok==1 { lw("PASS " as *u8) } else { lw("FAIL " as *u8) }
23 lw(what); lw("\n" as *u8)
24 return ok
25}
26
27func llen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
28
29func lslurp(path: *u8, buf: *u8, cap: i64) -> i64 {
30 let fd: i64 = sys_openat_rd(path)
31 if fd < 0 { return 0 - 1 }
32 var total: i64 = 0
33 var go: i64 = 1
34 while go == 1 {
35 let r: i64 = sys_read(fd, buf + total, cap - total)
36 if r <= 0 { go = 0 }
37 if r > 0 { total = total + r }
38 if total >= cap { go = 0 }
39 }
40 sys_close(fd)
41 return total
42}
43
44func lcontains(hay: *u8, hn: i64, needle: *u8) -> i64 {
45 var nl: i64 = 0
46 while needle[nl] != (0 as u8) { nl = nl + 1 }
47 if nl == 0 { return 1 }
48 if nl > hn { return 0 }
49 let last: i64 = hn - nl
50 var i: i64 = 0
51 while i <= last {
52 var j: i64 = 0
53 var hit: i64 = 1
54 while j < nl {
55 if (hay[i+j] as i64) != (needle[j] as i64) { hit = 0; j = nl }
56 if hit == 1 { j = j + 1 }
57 }
58 if hit == 1 { return 1 }
59 i = i + 1
60 }
61 return 0
62}
63
64func lbytes_eq(a: *u8, an: i64, b: *u8, bn: i64) -> i64 {
65 if an != bn { return 0 }
66 var i: i64 = 0
67 while i < an { if (a[i] as i64) != (b[i] as i64) { return 0 } i = i + 1 }
68 return 1
69}
70
71// parse an (untrusted, model-emitted) blueprint text + build it to path; returns output length in buf.
72func l_build(text: *u8, tn: i64, path: *u8, buf: *u8, cap: i64) -> i64 {
73 let kind: *i64 = sys_mmap(8*32) as *i64
74 let a: *i64 = sys_mmap(8*32) as *i64
75 let b: *i64 = sys_mmap(8*32) as *i64
76 let c: *i64 = sys_mmap(8*32) as *i64
77 let d: *i64 = sys_mmap(8*32) as *i64
78 let list: *i64 = sys_mmap(8*32) as *i64
79 let lcount: *i64 = sys_mmap(8*32) as *i64
80 let arena: *u8 = sys_mmap(65536)
81 let title: *u8 = sys_mmap(512)
82 let nblk: i64 = sgp_parse(text, tn, kind, a, b, c, d, list, lcount, 32, arena, title, 511)
83 let fd: i64 = sys_openat_wr(path, 0x1a4)
84 if fd >= 0 { sg_build_page(fd, title, kind, a, b, c, d, list, lcount, nblk); sys_close(fd) }
85 return lslurp(path, buf, cap)
86}
87
88func main() -> i64 {
89 var pass: i64 = 0
90 var rows: i64 = 0
91 var ok: i64 = 0
92
93 // M0 AI-OPTIONAL / SOURCE-INDEPENDENT: a model that emits the SAME records with blank + "thinking" lines
94 // builds BYTE-IDENTICAL to a clean hand-typed blueprint. The model's formatting noise cannot change the site.
95 let human: *u8 = "header|Acme|Get started|#go\nhero|Build fast|Ship today|Get started|#go\nsearch|/s|Find\ncards|What we do\ncard|Design|Beautiful sites\ncard|Deploy|One click\nsteps|3 steps\nstep|Plan\nstep|Build\nstep|Ship\ntrust|\nsig|Trusted by many\nfooter|Acme Inc\n" as *u8
96 let model: *u8 = "# model: here is the site\n\nheader|Acme|Get started|#go\n\nhero|Build fast|Ship today|Get started|#go\nsearch|/s|Find\n\ncards|What we do\ncard|Design|Beautiful sites\ncard|Deploy|One click\nsteps|3 steps\nstep|Plan\nstep|Build\nstep|Ship\ntrust|\nsig|Trusted by many\nfooter|Acme Inc\n" as *u8
97 let bh: *u8 = sys_mmap(262144); let lh: i64 = l_build(human, llen(human), "/tmp/nx_llm_human.html" as *u8, bh, 262143)
98 let bm: *u8 = sys_mmap(262144); let lm: i64 = l_build(model, llen(model), "/tmp/nx_llm_model.html" as *u8, bm, 262143)
99 ok = 0; if lh > 0 { if lbytes_eq(bh, lh, bm, lm) == 1 { ok = 1 } }
100 rows=rows+1; pass=pass+lrow(0, ok, "AI-optional: model output (blanks+comment) builds byte-identical to hand-typed (source-independent)" as *u8)
101
102 // M1 GOVERNANCE injection: model puts a <script> payload in a card title -> ESCAPED, never raw
103 let inj: *u8 = "header|Acme|Go|#go\nhero|H|sub|Go|#go\nsearch|/s|find\ncards|Svc\ncard|<script>alert(7)</script>|body\nsteps|S\nstep|one\ntrust|\nsig|s\nfooter|F\n" as *u8
104 let b1: *u8 = sys_mmap(262144); let l1: i64 = l_build(inj, llen(inj), "/tmp/nx_llm_inj.html" as *u8, b1, 262143)
105 ok = 0; if lcontains(b1, l1, "<script>alert(7)" as *u8) == 0 { if lcontains(b1, l1, "<script>alert(7)" as *u8) == 1 { ok = 1 } }
106 rows=rows+1; pass=pass+lrow(1, ok, "model cannot inject script: <script> payload escaped, never raw (governed)" as *u8)
107
108 // M2 GOVERNANCE non-compliant: model "forgets" the search -> REFUSED, 0 bytes (cannot ship a broken page)
109 let bad: *u8 = "header|Acme|Go|#go\nhero|H|sub|Go|#go\ncards|Svc\ncard|t|b\nsteps|S\nstep|one\ntrust|\nsig|s\nfooter|F\n" as *u8
110 let b2: *u8 = sys_mmap(262144); let l2: i64 = l_build(bad, llen(bad), "/tmp/nx_llm_bad.html" as *u8, b2, 262143)
111 ok = 0; if l2 == 0 { ok = 1 }
112 rows=rows+1; pass=pass+lrow(2, ok, "model cannot ship broken: non-UX-compliant proposal REFUSED, 0 bytes (governed)" as *u8)
113
114 // M3 GOVERNANCE hallucinated kinds: model invents block kinds -> skipped; valid blocks still build; no leak
115 let halluc: *u8 = "header|Acme|Go|#go\nhero|H|sub|Go|#go\nsearch|/s|find\ncarousel|img1|img2|img3\nparallax|on\ncards|Svc\ncard|Real Card|body\nsteps|S\nstep|one\ntrust|\nsig|s\nfooter|F\n" as *u8
116 let b3: *u8 = sys_mmap(262144); let l3: i64 = l_build(halluc, llen(halluc), "/tmp/nx_llm_halluc.html" as *u8, b3, 262143)
117 ok = 0; if l3 > 0 { if lcontains(b3, l3, "Real Card" as *u8) == 1 { if lcontains(b3, l3, "img1" as *u8) == 0 { if lcontains(b3, l3, "parallax" as *u8) == 0 { ok = 1 } } } }
118 rows=rows+1; pass=pass+lrow(3, ok, "model cannot crash/smuggle: hallucinated kinds skipped, valid blocks build, no leak" as *u8)
119
120 // M4 GOVERNANCE raw-markup smuggle: model puts <img onerror> in the footer text -> ESCAPED, never raw
121 let smug: *u8 = "header|Acme|Go|#go\nhero|H|sub|Go|#go\nsearch|/s|find\ncards|Svc\ncard|t|b\nsteps|S\nstep|one\ntrust|\nsig|s\nfooter|<img src=x onerror=alert(9)>\n" as *u8
122 let b4: *u8 = sys_mmap(262144); let l4: i64 = l_build(smug, llen(smug), "/tmp/nx_llm_smug.html" as *u8, b4, 262143)
123 ok = 0; if lcontains(b4, l4, "<img src=x onerror" as *u8) == 0 { if lcontains(b4, l4, "<img" as *u8) == 1 { ok = 1 } }
124 rows=rows+1; pass=pass+lrow(4, ok, "model cannot smuggle markup: raw <img onerror> escaped in a text field (governed)" as *u8)
125
126 // M5 DETERMINISM: a model proposal builds byte-identical twice (model nondeterminism quarantined to the proposal)
127 let b5: *u8 = sys_mmap(262144); let l5: i64 = l_build(inj, llen(inj), "/tmp/nx_llm_inj2.html" as *u8, b5, 262143)
128 ok = lbytes_eq(b1, l1, b5, l5)
129 rows=rows+1; pass=pass+lrow(5, ok, "deterministic: same model proposal -> byte-identical build (reproducible)" as *u8)
130
131 lw("NX-SITEGEN-LLM-GATE rows=" as *u8); lnum(rows); lw(" pass=" as *u8); lnum(pass); lw("\n" as *u8)
132 if pass == rows {
133 let line: *u8 = sys_mmap(256)
134 var off: i64 = lcat(line, 0, "CMSGATE row=nx_sitegen_llm site-builder-ai-seam rows=" as *u8)
135 off = lcatnum(line, off, rows)
136 off = lcat(line, off, " pass=" as *u8); off = lcatnum(line, off, pass)
137 off = lcat(line, off, " verdict=PASS\n" as *u8)
138 let gf: i64 = sys_openat_append("knowledge/status/cms_gate.log" as *u8, 0x1a4)
139 if gf >= 0 { sys_write(gf, line, off); sys_close(gf) }
140 lw("NX-SITEGEN-LLM-GATE verdict=PASS -- governed AI-optional seam recorded in cms_gate.log\n" as *u8)
141 sys_exit(0); return 0
142 }
143 lw("NX-SITEGEN-LLM-GATE verdict=FAIL -- NOT recorded (no fake-green)\n" as *u8)
144 sys_exit(1); return 1
145}