code wiki / _hdl_build / nx_sitegen_studio_gate.nx

nx_sitegen_studio_gate.nx source

↩ module page · 99 lines · 6614 B

1import "nx_gate_base.nx" 2// nx_sitegen_studio_gate.nx -- gate for the WYSIWYG studio (nx_sitegen_studio). Proves the sovereign /build 3// endpoint + the editor client WITHOUT a browser: se_build_site (the live-preview backend) builds a posted 4// blueprint through the governed engine, refuses an incomplete one, and escapes injection; se_editor_html 5// serves an editor client that is a thin shim (block palette + .site serialization + POST /build), with NO 6// site-build logic in it. Appends "CMSGATE row=nx_sitegen_studio site-builder-wysiwyg ... verdict=PASS" to 7// knowledge/status/cms_gate.log on all-pass. Exit 0 iff all pass. license_tier: ORIGINAL 8import "nx_sitegen_studio.nx" 9import "nx_syscalls.nx" 10 11func gnum(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 } 12func gcat(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 } 13func gcatnum(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 } 14 15func grow(id: i64, ok: i64, what: *u8) -> i64 { 16 gw("STUDIOROW " as *u8); gnum(id); gw(" " as *u8) 17 if ok==1 { gw("PASS " as *u8) } else { gw("FAIL " as *u8) } 18 gw(what); gw("\n" as *u8) 19 return ok 20} 21 22func glen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 23 24func gcontains(hay: *u8, hn: i64, needle: *u8) -> i64 { 25 var nl: i64 = 0 26 while needle[nl] != (0 as u8) { nl = nl + 1 } 27 if nl == 0 { return 1 } 28 if nl > hn { return 0 } 29 let last: i64 = hn - nl 30 var i: i64 = 0 31 while i <= last { 32 var j: i64 = 0 33 var hit: i64 = 1 34 while j < nl { 35 if (hay[i+j] as i64) != (needle[j] as i64) { hit = 0; j = nl } 36 if hit == 1 { j = j + 1 } 37 } 38 if hit == 1 { return 1 } 39 i = i + 1 40 } 41 return 0 42} 43 44func main() -> i64 { 45 var pass: i64 = 0 46 var rows: i64 = 0 47 var ok: i64 = 0 48 let out: *u8 = sys_mmap(262144) 49 50 // T0: /build renders a valid posted blueprint through the sovereign engine (the live preview backend) 51 let valid: *u8 = "title|Demo\nheader|Acme|Go|#go\nhero|Build fast|Yours|Go|#go\nsearch|/s|find\ncards|Svc\ncard|Design|Clean pages\nsteps|3 steps\nstep|one\ntrust|\nsig|trusted\nfooter|Acme\n" as *u8 52 let l0: i64 = se_build_site(valid, glen(valid), out, 262143) 53 ok = 0; if l0 > 0 { if gcontains(out, l0, "Build fast" as *u8)==1 { if gcontains(out, l0, "Design" as *u8)==1 { if gcontains(out, l0, "width=device-width" as *u8)==1 { ok=1 } } } } 54 rows=rows+1; pass=pass+grow(0, ok, "/build renders a posted blueprint via the sovereign engine (live preview backend)" as *u8) 55 56 // T1 (NEG): /build refuses an incomplete blueprint (no search) -> 0 bytes (cannot preview/ship a broken page) 57 let incomplete: *u8 = "title|Demo\nheader|Acme|Go|#go\nhero|H|s|Go|#go\ncards|Svc\ncard|t|b\nsteps|S\nstep|one\ntrust|\nsig|x\nfooter|F\n" as *u8 58 let l1: i64 = se_build_site(incomplete, glen(incomplete), out, 262143) 59 ok = 0; if l1 == 0 { ok = 1 } 60 rows=rows+1; pass=pass+grow(1, ok, "/build refuses an incomplete blueprint, 0 bytes (governed, neg control)" as *u8) 61 62 // T2 (NEG): /build escapes injection in a posted blueprint (a hostile post cannot inject script) 63 let inj: *u8 = "title|Demo\nheader|Acme|Go|#go\nhero|H|s|Go|#go\nsearch|/s|f\ncards|Svc\ncard|<script>alert(8)</script>|b\nsteps|S\nstep|one\ntrust|\nsig|x\nfooter|F\n" as *u8 64 let l2: i64 = se_build_site(inj, glen(inj), out, 262143) 65 ok = 0; if gcontains(out, l2, "<script>alert(8)" as *u8)==0 { if gcontains(out, l2, "&lt;script&gt;alert(8)" as *u8)==1 { ok=1 } } 66 rows=rows+1; pass=pass+grow(2, ok, "/build escapes a hostile posted blueprint (injection neutralized, neg control)" as *u8) 67 68 // T3: the editor client is served and is a THIN SHIM (palette + serialize + POST /build), no build logic 69 let ed: *u8 = sys_mmap(262144) 70 let le: i64 = se_editor_html(ed, 262143) 71 ok = 0 72 if le > 0 { 73 if gcontains(ed, le, "data-add=\"header\"" as *u8)==1 { if gcontains(ed, le, "data-add=\"footer\"" as *u8)==1 { 74 if gcontains(ed, le, "fetch(BUILD" as *u8)==1 { if gcontains(ed, le, "srcdoc" as *u8)==1 { 75 if gcontains(ed, le, "header|" as *u8)==1 { if gcontains(ed, le, "ZERO site-build logic" as *u8)==1 { ok=1 } } } } } } 76 } 77 rows=rows+1; pass=pass+grow(3, ok, "editor client served: block palette + .site serialize + POST /build, no build logic (thin shim)" as *u8) 78 79 // T4: round-trip -- a blueprint shaped like the editor's seed builds through /build (editor output == engine input) 80 let seed: *u8 = "title|My Nishi Site\nheader|Acme Co|Get started|#go\nhero|Build a real site, fast.|Sovereign, portable, yours.|Get started|#go\nsearch|/search|Search...\ncards|What we do\ncard|Design|Clean, responsive pages.\ncard|Own it|Your design is portable data.\nsteps|Get going in 3 steps\nstep|Add blocks\nstep|Preview live\nstep|Publish\ntrust|\nsig|Built sovereign, hardware up\nfooter|Acme Co -- built with Nishi Studio\n" as *u8 81 let l4: i64 = se_build_site(seed, glen(seed), out, 262143) 82 ok = 0; if l4 > 0 { if gcontains(out, l4, "Build a real site, fast." as *u8)==1 { if gcontains(out, l4, "Own it" as *u8)==1 { ok=1 } } } 83 rows=rows+1; pass=pass+grow(4, ok, "round-trip: the editor's seed blueprint builds through /build (editor output == engine input)" as *u8) 84 85 gw("NX-SITEGEN-STUDIO-GATE rows=" as *u8); gnum(rows); gw(" pass=" as *u8); gnum(pass); gw("\n" as *u8) 86 if pass == rows { 87 let line: *u8 = sys_mmap(256) 88 var off: i64 = gcat(line, 0, "CMSGATE row=nx_sitegen_studio site-builder-wysiwyg rows=" as *u8) 89 off = gcatnum(line, off, rows) 90 off = gcat(line, off, " pass=" as *u8); off = gcatnum(line, off, pass) 91 off = gcat(line, off, " verdict=PASS\n" as *u8) 92 let gf: i64 = sys_openat_append("knowledge/status/cms_gate.log" as *u8, 0x1a4) 93 if gf >= 0 { sys_write(gf, line, off); sys_close(gf) } 94 gw("NX-SITEGEN-STUDIO-GATE verdict=PASS -- sovereign WYSIWYG studio recorded in cms_gate.log\n" as *u8) 95 sys_exit(0); return 0 96 } 97 gw("NX-SITEGEN-STUDIO-GATE verdict=FAIL -- NOT recorded (no fake-green)\n" as *u8) 98 sys_exit(1); return 1 99}