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, "&lt;script&gt;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, "&lt;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}