nx_site_publish_gate.nx source
↩ module page · 90 lines · 4431 B
1// nx_site_publish_gate.nx -- gates artifact-publish placement semantics on a THROWAWAY CWD (the docroot
2// is CWD-relative sites/): fresh publish lands byte-identical; republish preserves .prev AND lands v2;
3// traversal ('..', absolute) DENIED with NOTHING written; secret-needle relpath DENIED via the IO layer;
4// absent source honest ABSENT. Runner: mkdir a scratch dir, cd into it, run. Exit 0 only on all-PASS.
5// license_tier: ORIGINAL expect_exit: 0
6import "nx_site_publish_lib.nx"
7import "nx_seg_store.nx" // ss_writefile -- fixture author
8
9const SG_CHECKS: i64 = 7
10const SG_AV: i64 = 64 // synthetic argv cells
11const SG_RB: i64 = 4096 // read-back buffer
12
13func sg_check(name: *u8, ok: i64, pass: *i64) -> i64 {
14 fsx_puts("T " as *u8); fsx_puts(name); fsx_puts(" -> " as *u8)
15 if ok == 1 { fsx_puts("PASS\n" as *u8); pass[0] = pass[0] + 1 } else { fsx_puts("FAIL\n" as *u8) }
16 return 0
17}
18func sg_run(src: *u8, site: *u8, rel: *u8) -> i64 {
19 let av: *i64 = sys_mmap(SG_AV) as *i64
20 av[0] = "nx_site_publish" as *u8 as i64
21 av[PB_ARG_VERB] = "publish" as *u8 as i64
22 av[PB_ARG_SRC] = src as i64
23 av[PB_ARG_SITE] = site as i64
24 av[PB_ARG_REL] = rel as i64
25 return sp_main(PB_ARGC, av)
26}
27func sg_eq(path: *u8, expect: *u8) -> i64 {
28 let b: *u8 = sys_mmap(SG_RB)
29 let n: i64 = vw_read(path, b, SG_RB - 1)
30 if n < 0 { return 0 }
31 b[n] = 0 as u8
32 return fsx_seq(b, expect)
33}
34func sg_absent(path: *u8) -> i64 {
35 let b: *u8 = sys_mmap(SG_RB)
36 if vw_read(path, b, SG_RB - 1) < 0 { return 1 }
37 return 0
38}
39
40func main() -> i64 {
41 let pass: *i64 = sys_mmap(16) as *i64
42 pass[0] = 0
43 sys_mkdir("sites" as *u8, 0x1ed)
44 sys_mkdir("sites/gatesite" as *u8, 0x1ed)
45 ss_writefile("v1.html" as *u8, "<h1>one</h1>" as *u8, vw_slen("<h1>one</h1>" as *u8))
46 ss_writefile("v2.html" as *u8, "<h1>two</h1>" as *u8, vw_slen("<h1>two</h1>" as *u8))
47 // T1 fresh publish lands byte-identical, no .prev
48 var ok1: i64 = 0
49 if sg_run("v1.html" as *u8, "gatesite" as *u8, "page.html" as *u8) == 0 {
50 if sg_eq("sites/gatesite/page.html" as *u8, "<h1>one</h1>" as *u8) == 1 {
51 ok1 = sg_absent("sites/gatesite/page.html.prev" as *u8)
52 }
53 }
54 sg_check("fresh-publish-lands" as *u8, ok1, pass)
55 // T2 republish: .prev holds v1, target holds v2
56 var ok2: i64 = 0
57 if sg_run("v2.html" as *u8, "gatesite" as *u8, "page.html" as *u8) == 0 {
58 if sg_eq("sites/gatesite/page.html" as *u8, "<h1>two</h1>" as *u8) == 1 {
59 ok2 = sg_eq("sites/gatesite/page.html.prev" as *u8, "<h1>one</h1>" as *u8)
60 }
61 }
62 sg_check("republish-preserves-prev" as *u8, ok2, pass)
63 // T3 traversal in relpath DENIED, nothing written outside
64 var ok3: i64 = 0
65 if sg_run("v1.html" as *u8, "gatesite" as *u8, "../escape.html" as *u8) == FSX_RC_DENIED {
66 ok3 = sg_absent("sites/escape.html" as *u8)
67 }
68 sg_check("relpath-traversal-denied" as *u8, ok3, pass)
69 // T4 absolute site DENIED
70 sg_check("absolute-site-denied" as *u8, (sg_run("v1.html" as *u8, "/etc" as *u8, "x.html" as *u8) == FSX_RC_DENIED) as i64, pass)
71 // T5 secret-needle relpath DENIED by the IO layer's write deny
72 sg_check("secret-relpath-denied" as *u8, (sg_run("v1.html" as *u8, "gatesite" as *u8, "apikey.html" as *u8) == FSX_RC_DENIED) as i64, pass)
73 // T6 absent source -> honest ABSENT
74 sg_check("absent-source-honest" as *u8, (sg_run("nope.html" as *u8, "gatesite" as *u8, "y.html" as *u8) == FSX_RC_ABSENT) as i64, pass)
75 // T7 REGRESSION (debt seq910): a relpath whose PARENT DIRECTORY does not exist must fail
76 // LOUD with FSX_RC_IO and write nothing. This is the case T1-T6 never covered -- the gate
77 // was 6/6 GREEN while the only silent exit in sp_main went untested, and a real publish to
78 // "research/rt004.html" returned empty output and read as success.
79 var ok7: i64 = 0
80 if sg_run("v1.html" as *u8, "gatesite" as *u8, "nodir/page.html" as *u8) == FSX_RC_IO {
81 ok7 = sg_absent("sites/gatesite/nodir/page.html" as *u8)
82 }
83 sg_check("missing-parent-dir-fails-loud" as *u8, ok7, pass)
84
85 fsx_puts("SITE-PUBLISH-GATE pass=" as *u8); fsx_putn(pass[0]); fsx_puts("/" as *u8); fsx_putn(SG_CHECKS); fsx_puts(" verdict=" as *u8)
86 if pass[0] == SG_CHECKS { fsx_puts("GREEN\n" as *u8); sys_exit(0); return 0 }
87 fsx_puts("RED\n" as *u8)
88 sys_exit(1)
89 return 1
90}