nx_site_publish_edge_canonical_gate_t139.nx source
↩ module page · 276 lines · 20819 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
8import "nx_gate_verdict.nx"
9
10const SG_CASES: *u8 = "fresh-publish-lands\nfirst-publish-retry-does-not-create-prev\nrepublish-preserves-prev\nchanged-publish-retry-retains-rollback\nbinary-difference-after-nul-and-retry\nrelpath-traversal-denied\nabsolute-site-denied\nordinary-key-name-allowed\nsecret-relpath-denied\nabsent-source-honest\nmissing-parent-dir-fails-loud\nguarded-create-exact\nwrong-artifact-pin-retains-live\nstale-live-pin-retains-live\nguarded-change-retains-predecessor\nguarded-retry-original-precondition\nguarded-reverse-retains-replaced-version\ncontended-target-refuses-without-wait\nreleased-lock-allows-retry\noversized-path-refused-before-construction\nstage-wrong-pin-creates-no-candidate\nstage-exact-candidate\nstage-retry-preserves-candidate\nstage-replacement-refused\nlegacy-publish-cannot-overwrite-staging\nguarded-publish-cannot-overwrite-staging\nstage-refuses-live-route\nstaging-alias-overwrites-refused\nregistered-site-config-written\nregistered-site-plane-seeded\nunregistered-stage-refused-without-placement\nrelease-identity-registered\nlegacy-publish-cannot-ignore-registered-hash\nregistered-stage-places-exact-bytes\nregistered-stage-retry-keeps-predecessor-absent\nconflicting-registration-cannot-authorize-replacement\nedge-register-consumer\nedge-exact-publish\nedge-idempotent\nedge-wrong-same-size-refuses-unchanged-success\nedge-dependency-lock-contention\nedge-registration-mismatch-refuses\nedge-source-size-change-refuses\nedge-owned-buffer-ignores-mutated-source-path\nedge-absent-reference-refuses\nedge-register-missing\nedge-missing-observed-failure\nedge-register-unreadable\nedge-unreadable-io-failure\nedge-traversal-refuses\nedge-self-lock-refuses\nedge-argc-refuses\nedge-register-output-failure-fixture\nedge-output-io-refuses-before-placement\nedge-valid-dev-full-actual-report-write-refuses\nlegacy-two-argument-locked-entry-compatible\n" as *u8
11static sg_plan: *i64
12const SG_ARG_CELL_BYTES: i64 = 8 // native x86-64 argv uses i64 pointer cells
13const SG_ARGV_BYTES: i64 = (PB_GUARDED_ARGC + 1) * SG_ARG_CELL_BYTES
14
15func sg_check(name: *u8, ok: i64, pass: *i64) -> i64 {
16 return gv_plan_check(sg_plan,name,ok,pass)
17}
18func sg_run(src: *u8, site: *u8, rel: *u8) -> i64 {
19 let av: *i64 = sys_mmap(SG_ARGV_BYTES) 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 let rc: i64 = sp_main(PB_ARGC,av)
26 sys_munmap(av as *u8,SG_ARGV_BYTES)
27 return rc
28}
29func sg_eq(path: *u8, expect: *u8) -> i64 {
30 return sg_eq_bytes(path,expect,vw_slen(expect))
31}
32func sg_eq_bytes(path: *u8, expect: *u8, expected_bytes: i64) -> i64 {
33 // One extra byte detects unexpected trailing content instead of accepting a prefix.
34 let read_bytes: i64 = expected_bytes+1
35 let b: *u8 = sys_mmap(read_bytes)
36 let n: i64 = vw_read(path,b,read_bytes)
37 let same: i64 = pb_same_bytes(b,n,expect,expected_bytes)
38 sys_munmap(b,read_bytes)
39 return same
40}
41func sg_absent(path: *u8) -> i64 {
42 let fd: i64 = sys_openat_rd(path)
43 // Linux ENOENT establishes absence; permission and other I/O failures do not.
44 if fd == (0-2) { return 1 }
45 if fd >= 0 { sys_close(fd) }
46 return 0
47}
48
49func main(argc: i64, argv: *i64) -> i64 {
50 if argc!=3{return 2}
51 let evidence_fd: i64=sys_openat_exclusive(argv[2] as *u8,FSX_MODE_RW)
52 if evidence_fd<0{return 4}
53 if sys_dup3(evidence_fd,1,0)<0{sys_close(evidence_fd);return 4}
54 if sys_close(evidence_fd)!=0{return 4}
55 // An explicit scratch directory must be new; refuse to run fixtures over an existing tree.
56 if argc > 1 {
57 let scratch: *u8 = argv[1] as *u8
58 if sys_mkdir(scratch, 0x1ed) != 0 { return 2 }
59 if sys_chdir(scratch) != 0 { return 2 }
60 }
61 let pass: *i64 = gv_ctr()
62 sg_plan = gv_plan_new(SG_CASES)
63 sys_mkdir("sites" as *u8, 0x1ed)
64 sys_mkdir("sites/gatesite" as *u8, 0x1ed)
65 ss_writefile("v1.html" as *u8, "<h1>one</h1>" as *u8, vw_slen("<h1>one</h1>" as *u8))
66 ss_writefile("v2.html" as *u8, "<h1>two</h1>" as *u8, vw_slen("<h1>two</h1>" as *u8))
67 // T1 fresh publish lands byte-identical, no .prev
68 var ok1: i64 = 0
69 if sg_run("v1.html" as *u8, "gatesite" as *u8, "page.html" as *u8) == 0 {
70 if sg_eq("sites/gatesite/page.html" as *u8, "<h1>one</h1>" as *u8) == 1 {
71 ok1 = sg_absent("sites/gatesite/page.html.prev" as *u8)
72 }
73 }
74 sg_check("fresh-publish-lands" as *u8, ok1, pass)
75 var retry1: i64 = 0
76 if sg_run("v1.html" as *u8, "gatesite" as *u8, "page.html" as *u8) == 0 {
77 if sg_eq("sites/gatesite/page.html" as *u8, "<h1>one</h1>" as *u8) == 1 {
78 retry1 = sg_absent("sites/gatesite/page.html.prev" as *u8)
79 }
80 }
81 sg_check("first-publish-retry-does-not-create-prev" as *u8, retry1, pass)
82 // T2 republish: .prev holds v1, target holds v2
83 var ok2: i64 = 0
84 if sg_run("v2.html" as *u8, "gatesite" as *u8, "page.html" as *u8) == 0 {
85 if sg_eq("sites/gatesite/page.html" as *u8, "<h1>two</h1>" as *u8) == 1 {
86 ok2 = sg_eq("sites/gatesite/page.html.prev" as *u8, "<h1>one</h1>" as *u8)
87 }
88 }
89 sg_check("republish-preserves-prev" as *u8, ok2, pass)
90 var retry2: i64 = 0
91 if sg_run("v2.html" as *u8, "gatesite" as *u8, "page.html" as *u8) == 0 {
92 if sg_eq("sites/gatesite/page.html" as *u8, "<h1>two</h1>" as *u8) == 1 {
93 retry2 = sg_eq("sites/gatesite/page.html.prev" as *u8, "<h1>one</h1>" as *u8)
94 }
95 }
96 sg_check("changed-publish-retry-retains-rollback" as *u8, retry2, pass)
97 let binary_bytes: i64 = 3 // fixture is exactly [A, NUL, B/C]
98 let binary1: *u8 = sys_mmap(binary_bytes)
99 let binary2: *u8 = sys_mmap(binary_bytes)
100 binary1[0] = 65 as u8; binary1[1] = 0 as u8; binary1[2] = 66 as u8
101 binary2[0] = 65 as u8; binary2[1] = 0 as u8; binary2[2] = 67 as u8
102 ss_writefile("binary1" as *u8, binary1, binary_bytes)
103 ss_writefile("binary2" as *u8, binary2, binary_bytes)
104 var binary_ok: i64 = 0
105 if sg_run("binary1" as *u8, "gatesite" as *u8, "asset.wasm" as *u8) == 0 {
106 if sg_run("binary2" as *u8, "gatesite" as *u8, "asset.wasm" as *u8) == 0 {
107 if sg_run("binary2" as *u8, "gatesite" as *u8, "asset.wasm" as *u8) == 0 {
108 if sg_eq_bytes("sites/gatesite/asset.wasm" as *u8,binary2,binary_bytes) == 1 {
109 binary_ok = sg_eq_bytes("sites/gatesite/asset.wasm.prev" as *u8,binary1,binary_bytes)
110 }
111 }
112 }
113 }
114 sg_check("binary-difference-after-nul-and-retry" as *u8, binary_ok, pass)
115 sys_munmap(binary1,binary_bytes); sys_munmap(binary2,binary_bytes)
116 // T3 traversal in relpath DENIED, nothing written outside
117 var ok3: i64 = 0
118 if sg_run("v1.html" as *u8, "gatesite" as *u8, "../escape.html" as *u8) == FSX_RC_DENIED {
119 ok3 = sg_absent("sites/escape.html" as *u8)
120 }
121 sg_check("relpath-traversal-denied" as *u8, ok3, pass)
122 // T4 absolute site DENIED
123 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)
124 // Policy distinguishes an ordinary key-containing name from a secret-bearing path.
125 sg_check("ordinary-key-name-allowed" as *u8, (sg_run("v1.html" as *u8, "gatesite" as *u8, "apikey.html" as *u8) == 0) as i64, pass)
126 var secret_ok: i64 = 0
127 if sg_run("v1.html" as *u8, "gatesite" as *u8, "api_secret.html" as *u8) == FSX_RC_DENIED {
128 secret_ok = sg_absent("sites/gatesite/api_secret.html" as *u8)
129 }
130 sg_check("secret-relpath-denied" as *u8, secret_ok, pass)
131 // T6 absent source -> honest ABSENT
132 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)
133 // T7 REGRESSION (debt seq910): a relpath whose PARENT DIRECTORY does not exist must fail
134 // LOUD with FSX_RC_IO and write nothing. This is the case T1-T6 never covered -- the gate
135 // was 6/6 GREEN while the only silent exit in sp_main went untested, and a real publish to
136 // "research/rt004.html" returned empty output and read as success.
137 var ok7: i64 = 0
138 if sg_run("v1.html" as *u8, "gatesite" as *u8, "nodir/page.html" as *u8) == FSX_RC_IO {
139 ok7 = sg_absent("sites/gatesite/nodir/page.html" as *u8)
140 }
141 sg_check("missing-parent-dir-fails-loud" as *u8, ok7, pass)
142
143 let av: *i64 = sys_mmap(SG_ARGV_BYTES) as *i64
144 let h1: *u8 = sys_mmap(PB_SHA_HEX+1)
145 let h2: *u8 = sys_mmap(PB_SHA_HEX+1)
146 pb_hash("<h1>one</h1>" as *u8,12,h1)
147 pb_hash("<h1>two</h1>" as *u8,12,h2)
148 av[0]="nx_site_publish" as *u8 as i64;av[1]="publish-guarded" as *u8 as i64
149 av[2]="v1.html" as *u8 as i64;av[3]="gatesite" as *u8 as i64
150 av[4]="guard.html" as *u8 as i64;av[5]=h1 as i64;av[6]="absent" as *u8 as i64
151 let fresh: i64 = sp_main(PB_GUARDED_ARGC,av)
152 sg_check("guarded-create-exact",((fresh==0)&&(sg_eq("sites/gatesite/guard.html" as *u8,"<h1>one</h1>" as *u8)==1)) as i64,pass)
153 av[2]="v2.html" as *u8 as i64;av[5]=h1 as i64;av[6]=h1 as i64
154 let wrong: i64 = sp_main(PB_GUARDED_ARGC,av)
155 sg_check("wrong-artifact-pin-retains-live",((wrong==PB_RC_CONFLICT)&&(sg_eq("sites/gatesite/guard.html" as *u8,"<h1>one</h1>" as *u8)==1)) as i64,pass)
156 av[5]=h2 as i64;av[6]="absent" as *u8 as i64
157 let stale: i64 = sp_main(PB_GUARDED_ARGC,av)
158 sg_check("stale-live-pin-retains-live",((stale==PB_RC_CONFLICT)&&(sg_absent("sites/gatesite/guard.html.prev" as *u8)==1)) as i64,pass)
159 av[6]=h1 as i64
160 let change: i64 = sp_main(PB_GUARDED_ARGC,av)
161 sg_check("guarded-change-retains-predecessor",((change==0)&&(sg_eq("sites/gatesite/guard.html.prev" as *u8,"<h1>one</h1>" as *u8)==1)) as i64,pass)
162 let retry: i64 = sp_main(PB_GUARDED_ARGC,av)
163 sg_check("guarded-retry-original-precondition",((retry==0)&&(sg_eq("sites/gatesite/guard.html.prev" as *u8,"<h1>one</h1>" as *u8)==1)) as i64,pass)
164 av[2]="v1.html" as *u8 as i64;av[5]=h1 as i64;av[6]=h2 as i64
165 let reverse: i64 = sp_main(PB_GUARDED_ARGC,av)
166 sg_check("guarded-reverse-retains-replaced-version",((reverse==0)&&(sg_eq("sites/gatesite/guard.html" as *u8,"<h1>one</h1>" as *u8)==1)&&(sg_eq("sites/gatesite/guard.html.prev" as *u8,"<h1>two</h1>" as *u8)==1)) as i64,pass)
167 let lockfd: i64 = sys_openat_wr("sites/gatesite/guard.html.publish-lock" as *u8,FSX_MODE_RW)
168 var held: i64 = 0
169 if lockfd >= 0 {
170 if sys_flock(lockfd,PB_LOCK_EX_NB)==0 { held=(sp_main(PB_GUARDED_ARGC,av)==PB_RC_BUSY) as i64 }
171 sys_close(lockfd)
172 }
173 sg_check("contended-target-refuses-without-wait",held,pass)
174 sg_check("released-lock-allows-retry",(sp_main(PB_GUARDED_ARGC,av)==0) as i64,pass)
175 let longrel: *u8 = sys_mmap(PB_PATH+1)
176 var li: i64 = 0
177 while li < PB_PATH { longrel[li]=97 as u8;li=li+1 };longrel[li]=0 as u8
178 av[4]=longrel as i64
179 sg_check("oversized-path-refused-before-construction",(sp_main(PB_GUARDED_ARGC,av)==FSX_RC_DENIED) as i64,pass)
180 sys_mkdir("sites/gatesite/releases" as *u8,0x1ed)
181 av[1]="stage" as *u8 as i64;av[2]="v1.html" as *u8 as i64
182 av[4]="releases/candidate.html" as *u8 as i64;av[5]=h2 as i64
183 sg_check("stage-wrong-pin-creates-no-candidate",((sp_main(PB_STAGE_ARGC,av)==PB_RC_CONFLICT)&&(sg_absent("sites/gatesite/releases/candidate.html" as *u8)==1)) as i64,pass)
184 av[5]=h1 as i64
185 sg_check("stage-exact-candidate",((sp_main(PB_STAGE_ARGC,av)==0)&&(sg_eq("sites/gatesite/releases/candidate.html" as *u8,"<h1>one</h1>" as *u8)==1)) as i64,pass)
186 sg_check("stage-retry-preserves-candidate",((sp_main(PB_STAGE_ARGC,av)==0)&&(sg_absent("sites/gatesite/releases/candidate.html.prev" as *u8)==1)) as i64,pass)
187 av[2]="v2.html" as *u8 as i64;av[5]=h2 as i64
188 sg_check("stage-replacement-refused",((sp_main(PB_STAGE_ARGC,av)==PB_RC_CONFLICT)&&(sg_eq("sites/gatesite/releases/candidate.html" as *u8,"<h1>one</h1>" as *u8)==1)) as i64,pass)
189 sg_check("legacy-publish-cannot-overwrite-staging",(sg_run("v2.html" as *u8,"gatesite" as *u8,"releases/candidate.html" as *u8)==PB_RC_CONFLICT) as i64,pass)
190 av[1]="publish-guarded" as *u8 as i64;av[6]=h1 as i64
191 sg_check("guarded-publish-cannot-overwrite-staging",(sp_main(PB_GUARDED_ARGC,av)==PB_RC_CONFLICT) as i64,pass)
192 av[1]="stage" as *u8 as i64;av[4]="page.html" as *u8 as i64
193 sg_check("stage-refuses-live-route",(sp_main(PB_STAGE_ARGC,av)==FSX_RC_DENIED) as i64,pass)
194 var aliases: i64 = 0
195 if sg_run("v2.html" as *u8,"gatesite" as *u8,"./releases/candidate.html" as *u8)==FSX_RC_DENIED {
196 if sg_run("v2.html" as *u8,"gatesite/releases" as *u8,"candidate.html" as *u8)==FSX_RC_DENIED {
197 if sg_run("v2.html" as *u8,"gatesite" as *u8,"releases//candidate.html" as *u8)==FSX_RC_DENIED {
198 aliases=sg_eq("sites/gatesite/releases/candidate.html" as *u8,"<h1>one</h1>" as *u8)
199 }
200 }
201 }
202 sg_check("staging-alias-overwrites-refused",aliases,pass)
203 sys_mkdir("knowledge" as *u8,0x1ed)
204 let rcfg: *u8 = "gatesite\tsites/gatesite\tknowledge/pub-\thttps://example.invalid\tGate\tprivate/\n" as *u8
205 sg_check("registered-site-config-written",ss_writefile("knowledge/pub_sites.conf" as *u8,rcfg,ss_len(rcfg)) == 0,pass)
206 let rw: *i64 = ss_begin_cap(64)
207 ss_add(rw,1,"q:n" as *u8,"0" as *u8,1)
208 sg_check("registered-site-plane-seeded",ss_commit("knowledge/pub-" as *u8,rw,ss_next_segid("knowledge/pub-" as *u8)) == 0,pass)
209 av[1]="stage" as *u8 as i64; av[2]="v1.html" as *u8 as i64
210 av[4]="releases/registered.html" as *u8 as i64; av[5]=h1 as i64
211 sg_check("unregistered-stage-refused-without-placement",((sp_main(PB_STAGE_ARGC,av)==PB_RC_CONFLICT)&&(sg_absent("sites/gatesite/releases/registered.html" as *u8)==1)) as i64,pass)
212 sg_check("release-identity-registered",pr_register("knowledge/pub-" as *u8,"releases/registered.html" as *u8,h1)==PR_CREATED,pass)
213 sg_check("legacy-publish-cannot-ignore-registered-hash",((sg_run("v2.html" as *u8,"gatesite" as *u8,"releases/registered.html" as *u8)==PB_RC_CONFLICT)&&(sg_absent("sites/gatesite/releases/registered.html" as *u8)==1)) as i64,pass)
214 sg_check("registered-stage-places-exact-bytes",((sp_main(PB_STAGE_ARGC,av)==0)&&(sg_eq("sites/gatesite/releases/registered.html" as *u8,"<h1>one</h1>" as *u8)==1)) as i64,pass)
215 sg_check("registered-stage-retry-keeps-predecessor-absent",((sp_main(PB_STAGE_ARGC,av)==0)&&(sg_absent("sites/gatesite/releases/registered.html.prev" as *u8)==1)) as i64,pass)
216 sg_check("conflicting-registration-cannot-authorize-replacement",((pr_register("knowledge/pub-" as *u8,"releases/registered.html" as *u8,h2)==PR_CONFLICT)&&(sg_eq("sites/gatesite/releases/registered.html" as *u8,"<h1>one</h1>" as *u8)==1)) as i64,pass)
217
218 let edgebody: *u8="<script src='/releases/registered.html'></script>";let en: i64=vw_slen(edgebody)
219 let eh: *u8=sys_mmap(65);pb_hash(edgebody,en,eh)
220 ss_writefile("edge-source.html",edgebody,en)
221 sg_check("edge-register-consumer",pr_register("knowledge/pub-","releases/edge.html",eh)==PR_CREATED,pass)
222 let ea: *i64=sys_mmap(88) as *i64
223 ea[0]="nx_site_publish" as *u8 as i64;ea[1]="publish-guarded-edge" as *u8 as i64;ea[2]="edge-source.html" as *u8 as i64;ea[3]="gatesite" as *u8 as i64;ea[4]="releases/edge.html" as *u8 as i64
224 ea[5]=eh as i64;ea[6]="absent" as *u8 as i64;let ens: *u8=sys_mmap(32);let eno: i64=pl_catn(ens,0,en);ens[eno]=0;ea[7]=ens as i64;ea[8]="releases/registered.html" as *u8 as i64;ea[9]=h1 as i64;ea[10]=0
225 sg_check("edge-exact-publish",sp_main(10,ea)==0&&sg_eq("sites/gatesite/releases/edge.html",edgebody)==1,pass)
226 sg_check("edge-idempotent",sp_main(10,ea)==0&&sg_absent("sites/gatesite/releases/edge.html.prev")==1,pass)
227 ss_writefile("sites/gatesite/releases/registered.html","<h1>two</h1>",12)
228 sg_check("edge-wrong-same-size-refuses-unchanged-success",sp_main(10,ea)==PB_RC_CONFLICT&&sg_eq("sites/gatesite/releases/edge.html",edgebody)==1&&sg_absent("sites/gatesite/releases/edge.html.prev")==1,pass)
229 ss_writefile("sites/gatesite/releases/registered.html","<h1>one</h1>",12)
230 let dlock: i64=sys_openat_wr("sites/gatesite/releases/registered.html.publish-lock",FSX_MODE_RW)
231 var dbusy: i64=0;if dlock>=0{if sys_flock(dlock,PB_LOCK_EX_NB)==0{dbusy=(sp_main(10,ea)==PB_RC_BUSY) as i64};sys_close(dlock)}
232 sg_check("edge-dependency-lock-contention",dbusy,pass)
233 ea[9]=h2 as i64;sg_check("edge-registration-mismatch-refuses",sp_main(10,ea)==PB_RC_CONFLICT,pass);ea[9]=h1 as i64
234 ss_writefile("edge-source.html","<h1>two</h1>",12)
235 sg_check("edge-source-size-change-refuses",sp_main(10,ea)==PB_RC_CONFLICT&&sg_eq("sites/gatesite/releases/edge.html",edgebody)==1,pass)
236 // Deliberately change the pathname while retaining the already-owned bytes.
237 // This invokes the exact production snapshot check, without claiming full concurrent placement coverage.
238 sg_check("edge-owned-buffer-ignores-mutated-source-path",pe_check(edgebody,en,ea,"releases/registered.html",h1)==0,pass)
239 let no_ref: *u8="<script src='/releases/unselected.html'></script>";let nh: *u8=sys_mmap(65);pb_hash(no_ref,vw_slen(no_ref),nh);ea[5]=nh as i64
240 sg_check("edge-absent-reference-refuses",pe_check(no_ref,vw_slen(no_ref),ea,"releases/registered.html",h1)==PB_RC_CONFLICT,pass);ea[5]=eh as i64
241 sg_check("edge-register-missing",pr_register("knowledge/pub-","releases/missing.wasm",h1)==PR_CREATED,pass)
242 sg_check("edge-missing-observed-failure",pe_check(edgebody,en,ea,"releases/missing.wasm",h1)==PB_RC_CONFLICT,pass)
243 sg_check("edge-register-unreadable",pr_register("knowledge/pub-","releases/directory.wasm",h1)==PR_CREATED,pass);sys_mkdir("sites/gatesite/releases/directory.wasm",0x1ed)
244 sg_check("edge-unreadable-io-failure",pe_check(edgebody,en,ea,"releases/directory.wasm",h1)==FSX_RC_IO,pass)
245 ea[8]="../bad" as *u8 as i64;sg_check("edge-traversal-refuses",sp_main(10,ea)==FSX_RC_DENIED,pass)
246 ea[8]=ea[4];sg_check("edge-self-lock-refuses",sp_main(10,ea)==FSX_RC_DENIED,pass)
247 sg_check("edge-argc-refuses",sp_main(9,ea)==PB_RC_USAGE,pass)
248
249 sys_munmap(av as *u8,SG_ARGV_BYTES)
250
251 ss_writefile("edge-source.html",edgebody,en);ea[8]="releases/registered.html" as *u8 as i64;ea[4]="releases/outputfail.html" as *u8 as i64
252 sg_check("edge-register-output-failure-fixture",pr_register("knowledge/pub-","releases/outputfail.html",eh)==PR_CREATED,pass)
253 let child: i64=sys_fork();var output_failed: i64=0
254 if child==0{sys_close(1);let cr: i64=sp_main(10,ea);sys_exit(cr);return cr}
255 if child>0{let status: *i64=sys_mmap(8) as *i64;status[0]=0;if sys_wait4(child,status,0)==child{output_failed=(status[0]==FSX_RC_IO*256) as i64};sys_munmap(status as *u8,8)}
256 sg_check("edge-output-io-refuses-before-placement",output_failed==1&&sg_absent("sites/gatesite/releases/outputfail.html")==1&&sg_absent("sites/gatesite/releases/outputfail.html.prev")==1,pass)
257
258
259 let full_child: i64=sys_fork();var full_failed: i64=0
260 if full_child==0 {
261 let fullfd: i64=sys_openat_wr("/dev/full",FSX_MODE_RW)
262 if fullfd<0{sys_exit(2);return 2}
263 if sys_dup3(fullfd,1,0)<0{sys_exit(2);return 2};sys_close(fullfd)
264 // Bypass admission deliberately: this exact production decision must reject actual report write failure.
265 let fr: i64=pe_check(edgebody,en,ea,"releases/registered.html",h1);sys_exit(fr);return fr
266 }
267 if full_child>0{let fs: *i64=sys_mmap(8) as *i64;fs[0]=0;if sys_wait4(full_child,fs,0)==full_child{full_failed=(fs[0]==FSX_RC_IO*256) as i64};sys_munmap(fs as *u8,8)}
268 sg_check("edge-valid-dev-full-actual-report-write-refuses",full_failed==1&&sg_absent("sites/gatesite/releases/outputfail.html")==1,pass)
269
270 sg_check("legacy-two-argument-locked-entry-compatible",pb_publish_locked(PB_STAGE_ARGC,av)==0&&sg_eq("sites/gatesite/releases/registered.html","<h1>one</h1>")==1,pass)
271 gv_plan_finish(sg_plan,pass)
272 let result: i64=gv_verdict("SITE-PUBLISH-EDGE-PRIVATE-GATE" as *u8,pass,"atomic publication, retry preservation, selected-edge snapshot and immutable registration" as *u8)
273 if sys_fsync(1)!=0{return 4}
274 if sys_close(1)!=0{return 4}
275 return result
276}