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, "<script>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}