nx_wpt_ingest_gate.nx source
↩ module page · 489 lines · 24343 B
1// nx_wpt_ingest_gate.nx -- IN-PROCESS gate for BR21 (nx_wpt_acquire_lib, carried by nx_wpt_ingest).
2//
3// THE ANTI-VACUITY TOOTH IS THE WHOLE POINT AND IT IS NAMED. The defect BR21 closes is that the hand
4// acquisition path re-emitted every body through a TEXT TOOL ARGUMENT -- a NUL-terminated C string --
5// and html/syntax/parsing-html-fragments is the ENCODING-DETECTION suite, whose fixtures are UTF-16LE
6// with a BOM and therefore carry a NUL as their FOURTH BYTE. An ASCII fixture round-trips perfectly
7// through the broken path, so an ASCII fixture is a test the defect cannot fail. Every byte-exactness
8// tooth below runs on a UTF-16LE-with-BOM body built at RUNTIME, and the fixture is first asserted to
9// actually contain the NUL before any outcome is read: assert the fixture reached the condition
10// BEFORE asserting the outcome.
11//
12// THE HASH ANCHOR COMES FROM OUTSIDE THE ESTATE. wa_verify_blob compares against the git blob object
13// name GitHub declares. One tooth pins that arithmetic to f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f,
14// which is git hash-object of the three bytes abc under git 2.49.0 -- a value this estate did not
15// choose and cannot influence. Without it, computing a digest with swhid and then checking it with
16// swhid would prove plumbing and call it correctness.
17//
18// SCOPE, STATED: this gate is OFFLINE by construction. It proves the manifest parser, the dual
19// verification, the raw write, the read-back compare, the pin rule, the name allowlist, the
20// completeness conjunction and the manifest/marker emit. It does NOT prove the transport -- that is
21// nx_https_fetch_follow's subject, and the end-to-end proof is the live re-ingest reproducing
22// corpus_sha16 54e90b086e0c6530 and 1819a1dcd3030f03, recorded on browser.plan, not here.
23//
24// license_tier: ORIGINAL
25
26import "nx_syscalls.nx"
27import "nx_gate_verdict.nx"
28import "nx_wpt_acquire_lib.nx"
29
30const GT_DIR: *u8 = "/tmp/wsp_gate"
31const GT_FIX_CAP: i64 = 65536
32const GT_JSON_CAP: i64 = 65536
33const GT_BOM0: i64 = 255
34const GT_BOM1: i64 = 254
35const GT_FIX_LEN: i64 = 72 // DERIVED: 2 BOM bytes + 2 bytes per char of a 35-char title
36const GT_FIX_CSTR: i64 = 3 // DERIVED: BOM, BOM, first char -- then the NUL a C string stops at
37const GT_NUMBUF: i64 = 64 // DERIVED: a 64-bit decimal is at most 20 digits, plus a sign and a NUL
38const GT_SIZE_A: i64 = 1204 // the size GitHub declares for DOMTokenList-Iterable.html at the pin
39const GT_SIZE_B: i64 = 1205 // GT_SIZE_A + 1: the nearest neighbour, so the renderer cannot be a constant
40const GT_DIGITS_A: i64 = 5 // DERIVED: one char for the zero, plus the four digits of GT_SIZE_A
41const GT_DIGITS_B: i64 = 4 // DERIVED: the digit count of GT_SIZE_B
42
43// ---- RUNTIME FIXTURE BUILDERS (a detector that scans source finds its own fixtures) -------------
44
45func gt_utf16le(d: *u8) -> i64 {
46 d[0] = GT_BOM0 as u8
47 d[1] = GT_BOM1 as u8
48 let s: *u8 = "<title>WPT encoding fixture</title>" as *u8
49 var i: i64 = 0
50 var o: i64 = 2
51 while s[i] != (0 as u8) {
52 d[o] = s[i]
53 o = o + 1
54 d[o] = 0 as u8
55 o = o + 1
56 i = i + 1
57 }
58 return o
59}
60
61func gt_q(d: *u8, o: i64) -> i64 { d[o] = 34 as u8; return o + 1 }
62func gt_ch(d: *u8, o: i64, c: i64) -> i64 { d[o] = c as u8; return o + 1 }
63func gt_kv(d: *u8, o: i64, k: *u8, v: *u8) -> i64 {
64 var p: i64 = gt_q(d, o)
65 p = wsp_scat(d, p, k)
66 p = gt_q(d, p)
67 p = gt_ch(d, p, 58)
68 p = gt_ch(d, p, 32)
69 p = gt_q(d, p)
70 p = wsp_scat(d, p, v)
71 p = gt_q(d, p)
72 p = gt_ch(d, p, 44)
73 p = gt_ch(d, p, 10)
74 return p
75}
76func gt_kn(d: *u8, o: i64, k: *u8, v: i64) -> i64 {
77 var p: i64 = gt_q(d, o)
78 p = wsp_scat(d, p, k)
79 p = gt_q(d, p)
80 p = gt_ch(d, p, 58)
81 p = gt_ch(d, p, 32)
82 p = wa_mf_num(d, p, v)
83 p = gt_ch(d, p, 44)
84 p = gt_ch(d, p, 10)
85 return p
86}
87// one contents-API record in GitHub's real field order, including the path and download_url values
88// that carry the file name -- so a parser matching a key without its quotes would be caught here.
89func gt_rec(d: *u8, o: i64, name: *u8, sha: *u8, size: i64, typ: *u8, with_sha: i64) -> i64 {
90 var p: i64 = gt_ch(d, o, 123)
91 p = gt_ch(d, p, 10)
92 p = gt_kv(d, p, "name" as *u8, name)
93 let pathbuf: *u8 = sys_mmap(1024)
94 var q: i64 = wsp_scat(pathbuf, 0, "dom/lists/" as *u8)
95 q = wsp_scat(pathbuf, q, name)
96 pathbuf[q] = 0 as u8
97 p = gt_kv(d, p, "path" as *u8, pathbuf)
98 if with_sha == 1 { p = gt_kv(d, p, "sha" as *u8, sha) }
99 p = gt_kn(d, p, "size" as *u8, size)
100 let dl: *u8 = sys_mmap(1024)
101 var r: i64 = wsp_scat(dl, 0, "https://raw.githubusercontent.com/web-platform-tests/wpt/dead/dom/lists/" as *u8)
102 r = wsp_scat(dl, r, name)
103 dl[r] = 0 as u8
104 p = gt_kv(d, p, "download_url" as *u8, dl)
105 p = gt_kv(d, p, "type" as *u8, typ)
106 p = gt_ch(d, p, 125)
107 p = gt_ch(d, p, 44)
108 p = gt_ch(d, p, 10)
109 return p
110}
111
112func gt_path(out: *u8, leaf: *u8) -> i64 {
113 var p: i64 = wsp_scat(out, 0, GT_DIR)
114 p = wsp_scat(out, p, "/" as *u8)
115 p = wsp_scat(out, p, leaf)
116 out[p] = 0 as u8
117 return p
118}
119func gt_exists(path: *u8) -> i64 {
120 let fd: i64 = sys_openat_rd(path)
121 if fd < 0 { return 0 }
122 sys_close(fd)
123 return 1
124}
125func gt_zero(rep: *i64) -> i64 { var i: i64 = 0; while i < WA_R_SLOTS { rep[i] = 0; i = i + 1 } return 0 }
126
127func gt_blobsha(data: *u8, n: i64, out: *u8) -> i64 {
128 let id: *u8 = sys_mmap(WA_ID_CAP)
129 let r: i64 = swhid_cnt(data, n, id)
130 if r < 0 { return 0 }
131 var i: i64 = 0
132 while i < WA_SHA_HEX { out[i] = id[WA_SWHID_PREFIX + i]; i = i + 1 }
133 out[WA_SHA_HEX] = 0 as u8
134 return 1
135}
136func gt_hexeq(a: *u8, b: *u8) -> i64 {
137 var i: i64 = 0
138 while i < WA_SHA_HEX { if a[i] != b[i] { return 0 } i = i + 1 }
139 return 1
140}
141
142func main() -> i64 {
143 gv_head("nx_wpt_ingest_gate -- BR21 byte-preserving WPT corpus ingest" as *u8)
144 let ctr: *i64 = gv_ctr()
145
146 // ---- SETUP. Idempotent by construction: every fixture is unlinked first, so a run reports on
147 // itself and never on the leavings of the previous one. Gate scratch lives under /tmp, never
148 // beside a production tree.
149 sys_mkdir(GT_DIR, MODE_0755)
150 let p_ok: *u8 = sys_mmap(WA_PATH_CAP)
151 let p_tr: *u8 = sys_mmap(WA_PATH_CAP)
152 let p_bad: *u8 = sys_mmap(WA_PATH_CAP)
153 let p_mf: *u8 = sys_mmap(WA_PATH_CAP)
154 let p_mk: *u8 = sys_mmap(WA_PATH_CAP)
155 gt_path(p_ok, "utf16le-bom.html" as *u8)
156 gt_path(p_tr, "nul-truncated.html" as *u8)
157 gt_path(p_bad, "never-written.html" as *u8)
158 gt_path(p_mf, "MANIFEST.tsv" as *u8)
159 wa_marker_path(GT_DIR, p_mk)
160 sys_unlinkat(p_ok)
161 sys_unlinkat(p_tr)
162 sys_unlinkat(p_bad)
163 sys_unlinkat(p_mf)
164 sys_unlinkat(p_mk)
165 gv_need("setup-scratch-dir-is-writable" as *u8, gt_exists(GT_DIR), ctr)
166 var clean: i64 = 0
167 if gt_exists(p_ok) == 0 { clean = 1 }
168 gv_need("setup-left-no-fixture-behind" as *u8, clean, ctr)
169
170 // ---- THE FIXTURE, AND THE PROOF IT CAN FAIL ------------------------------------------------
171 let f: *u8 = sys_mmap(GT_FIX_CAP)
172 let n: i64 = gt_utf16le(f)
173 let cstr: i64 = wa_strlen(f)
174 gv_puts(" fixture: bytes=" as *u8); gv_num(n)
175 gv_puts(" b0=" as *u8); gv_num(f[0] as i64)
176 gv_puts(" b1=" as *u8); gv_num(f[1] as i64)
177 gv_puts(" b3=" as *u8); gv_num(f[3] as i64)
178 gv_puts(" c_string_length=" as *u8); gv_num(cstr); gv_puts("\n" as *u8)
179 var t_bom: i64 = 0
180 if (f[0] as i64) == GT_BOM0 { if (f[1] as i64) == GT_BOM1 { t_bom = 1 } }
181 gv_check("fixture-is-utf16le-with-a-bom" as *u8, t_bom, ctr)
182 var t_nul: i64 = 0
183 if n > GT_FIX_CSTR { if (f[3] as i64) == 0 { t_nul = 1 } }
184 gv_check("fixture-carries-an-embedded-nul-at-byte-3-so-the-defect-can-fire" as *u8, t_nul, ctr)
185 var t_arith: i64 = 0
186 if cstr == GT_FIX_CSTR { if n == GT_FIX_LEN { t_arith = 1 } }
187 gv_check("fixture-a-c-string-carrier-sees-3-bytes-where-the-file-has-72" as *u8, t_arith, ctr)
188
189 // ---- THE EXTERNAL HASH ANCHOR ---------------------------------------------------------------
190 let kat: *u8 = sys_mmap(64)
191 gt_blobsha("abc" as *u8, 3, kat)
192 gv_puts(" blob sha of abc = " as *u8); gv_puts(kat); gv_puts("\n" as *u8)
193 let kat_hit: i64 = gt_hexeq(kat, "f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f" as *u8)
194 let kat_miss: i64 = gt_hexeq(kat, "f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7e" as *u8)
195 gv_bite("blob-sha-hits-the-git-2-49-0-vector-for-abc-and-misses-a-one-nibble-neighbour" as *u8, kat_hit, kat_miss, ctr)
196
197 // ---- VERIFICATION ---------------------------------------------------------------------------
198 let sha: *u8 = sys_mmap(64)
199 gt_blobsha(f, n, sha)
200 var t_v0: i64 = 0
201 if wa_verify_blob(f, n, n, sha) == 0 { t_v0 = 1 }
202 gv_check("verify-accepts-a-body-matching-both-declared-numbers" as *u8, t_v0, ctr)
203 var t_v1: i64 = 0
204 if wa_verify_blob(f, n, n + 1, sha) == 1 { t_v1 = 1 }
205 gv_check("neg-control-verify-refuses-a-declared-size-one-too-large" as *u8, t_v1, ctr)
206 var t_v2: i64 = 0
207 if wa_verify_blob(f, GT_FIX_CSTR, n, sha) == 1 { t_v2 = 1 }
208 gv_check("neg-control-verify-refuses-a-nul-truncated-body" as *u8, t_v2, ctr)
209
210 // A BYTE SWAP PRESERVES LENGTH, so this is the tooth proving the sha leg is load-bearing rather
211 // than decoration beside the size check.
212 let g: *u8 = sys_mmap(GT_FIX_CAP)
213 var c: i64 = 0
214 while c < n { g[c] = f[c]; c = c + 1 }
215 let swap: i64 = g[4] as i64
216 g[4] = g[6]
217 g[6] = swap as u8
218 let vg: i64 = wa_verify_blob(g, n, n, sha)
219 gv_puts(" byte-swapped copy: same length=" as *u8); gv_num(n)
220 gv_puts(" verify_code=" as *u8); gv_num(vg); gv_puts(" (1 size, 2 sha)\n" as *u8)
221 var t_swapfix: i64 = 0
222 if (g[4] as i64) != (f[4] as i64) { t_swapfix = 1 }
223 gv_check("fixture-the-swap-really-changed-a-byte" as *u8, t_swapfix, ctr)
224 var t_v3: i64 = 0
225 if vg == 2 { t_v3 = 1 }
226 gv_check("neg-control-verify-catches-a-byte-swap-on-the-sha-which-the-size-check-cannot-see" as *u8, t_v3, ctr)
227
228 // ---- RAW WRITE AND READ-BACK ----------------------------------------------------------------
229 var t_w: i64 = 0
230 if wa_write_raw(p_ok, f, n) == 0 { t_w = 1 }
231 gv_check("write-raw-reports-success-on-the-utf16le-body" as *u8, t_w, ctr)
232 var t_rb: i64 = 0
233 if wa_readback_eq(p_ok, f, n) == 1 { t_rb = 1 }
234 gv_check("readback-is-byte-identical-to-the-utf16le-body" as *u8, t_rb, ctr)
235
236 let lp: *i64 = sys_mmap(16) as *i64
237 lp[0] = 0
238 let back: *u8 = sys_read_file(p_ok, lp)
239 var len_ok: i64 = 0
240 var bom_ok: i64 = 0
241 if (back as i64) != 0 {
242 if lp[0] == n { if n == GT_FIX_LEN { len_ok = 1 } }
243 if (back[0] as i64) == GT_BOM0 { if (back[1] as i64) == GT_BOM1 { bom_ok = 1 } }
244 }
245 gv_puts(" read back: bytes=" as *u8); gv_num(lp[0]); gv_puts("\n" as *u8)
246 gv_check("readback-length-on-disk-is-72-not-3" as *u8, len_ok, ctr)
247 gv_check("readback-preserves-both-bom-bytes" as *u8, bom_ok, ctr)
248
249 // THE DEFECT ITSELF, PLANTED: write only up to the first NUL, which is exactly what a text
250 // argument carrier does, and prove the read-back compare refuses it.
251 var t_plant: i64 = 0
252 if wa_write_raw(p_tr, f, cstr) == 0 { if wa_readback_eq(p_tr, f, n) == 0 { t_plant = 1 } }
253 gv_check("neg-control-a-nul-truncated-write-is-caught-by-the-readback-compare" as *u8, t_plant, ctr)
254
255 // ---- LAND ONE -------------------------------------------------------------------------------
256 let rep: *i64 = sys_mmap(WA_R_SLOTS * 8) as *i64
257 gt_zero(rep)
258 sys_unlinkat(p_ok)
259 let nm_ok: *u8 = "utf16le-bom.html" as *u8
260 let rc1: i64 = wa_land_one(GT_DIR, nm_ok, wa_strlen(nm_ok), f, n, n, sha, rep)
261 var t_l1: i64 = 0
262 if rc1 == 0 { if rep[WA_R_LANDED] == 1 { t_l1 = 1 } }
263 gv_check("land-one-lands-a-verified-body-and-counts-it" as *u8, t_l1, ctr)
264 let rc2: i64 = wa_land_one(GT_DIR, nm_ok, wa_strlen(nm_ok), f, n, n, sha, rep)
265 var t_l2: i64 = 0
266 if rc2 == 0 { if rep[WA_R_LANDED] == 2 { if wa_readback_eq(p_ok, f, n) == 1 { t_l2 = 1 } } }
267 gv_check("land-one-is-idempotent-and-the-second-landing-is-byte-identical" as *u8, t_l2, ctr)
268 var t_ag: i64 = 0
269 if wa_already_good(GT_DIR, nm_ok, wa_strlen(nm_ok), n, sha) == 1 { t_ag = 1 }
270 gv_check("already-good-sees-a-file-satisfying-both-declared-numbers" as *u8, t_ag, ctr)
271 var t_ag2: i64 = 0
272 if wa_already_good(GT_DIR, nm_ok, wa_strlen(nm_ok), n + 1, sha) == 0 { t_ag2 = 1 }
273 gv_check("neg-control-already-good-refuses-when-the-declared-size-differs" as *u8, t_ag2, ctr)
274
275 // A BODY THAT FAILS VERIFICATION MUST NEVER REACH THE DISK: a corrupt file is indistinguishable
276 // from a good one to every later reader, and the runner would fold it into a corpus_sha.
277 gt_zero(rep)
278 let nm_bad: *u8 = "never-written.html" as *u8
279 let rc3: i64 = wa_land_one(GT_DIR, nm_bad, wa_strlen(nm_bad), f, n, n, kat, rep)
280 var t_l3: i64 = 0
281 if rc3 == 2 { if rep[WA_R_FAIL_SHA] == 1 { t_l3 = 1 } }
282 gv_check("neg-control-land-one-refuses-a-body-whose-blob-sha-differs" as *u8, t_l3, ctr)
283 var t_l4: i64 = 0
284 if gt_exists(p_bad) == 0 { t_l4 = 1 }
285 gv_check("neg-control-a-refused-body-left-no-file-on-disk" as *u8, t_l4, ctr)
286
287 gt_zero(rep)
288 let nm_esc: *u8 = "../escaped.html" as *u8
289 let rc4: i64 = wa_land_one(GT_DIR, nm_esc, wa_strlen(nm_esc), f, n, n, sha, rep)
290 var t_l5: i64 = 0
291 if rc4 == 5 { if rep[WA_R_REFUSED_NAME] == 1 { t_l5 = 1 } }
292 gv_check("neg-control-land-one-refuses-a-parent-traversal-name" as *u8, t_l5, ctr)
293
294 // ---- THE SHARED DECIMAL RENDERER ------------------------------------------------------------
295 // wa_mf_num is the ONE decimal renderer in the lib -- wa_putn composes it rather than carrying a
296 // second copy, and every size written into MANIFEST.tsv goes through it. Zero is the case a
297 // hand-rolled renderer gets wrong, so it is the case tested first.
298 let nb: *u8 = sys_mmap(GT_NUMBUF)
299 var no: i64 = wa_mf_num(nb, 0, 0)
300 no = wa_mf_num(nb, no, GT_SIZE_A)
301 nb[no] = 0 as u8
302 gv_puts(" wa_mf_num zero then GT_SIZE_A = " as *u8); gv_puts(nb)
303 gv_puts(" offset=" as *u8); gv_num(no); gv_puts("\n" as *u8)
304 var t_d0: i64 = 0
305 if no == GT_DIGITS_A { if wa_find(nb, GT_DIGITS_A, 0, "01204" as *u8) == 0 { t_d0 = 1 } }
306 gv_check("decimal-renderer-writes-zero-then-1204-and-returns-the-right-offset" as *u8, t_d0, ctr)
307 let nb2: *u8 = sys_mmap(GT_NUMBUF)
308 let no2: i64 = wa_mf_num(nb2, 0, GT_SIZE_B)
309 var t_d1: i64 = 0
310 if no2 == GT_DIGITS_B { if wa_find(nb2, GT_DIGITS_B, 0, "1205" as *u8) == 0 { t_d1 = 1 } }
311 gv_check("neg-control-decimal-renderer-renders-1205-differently-from-1204" as *u8, t_d1, ctr)
312
313 // ---- THE PIN --------------------------------------------------------------------------------
314 let pin_good: i64 = wa_is_pin("a7b5671e50ee3610ec3ad2e1278a33b2cb11339c" as *u8)
315 let pin_branch: i64 = wa_is_pin("main" as *u8)
316 gv_bite("pin-accepts-a-40-hex-commit-and-refuses-a-branch-name" as *u8, pin_good, pin_branch, ctr)
317 var t_p2: i64 = 0
318 if wa_is_pin("A7B5671E50EE3610EC3AD2E1278A33B2CB11339C" as *u8) == 0 { t_p2 = 1 }
319 gv_check("neg-control-pin-refuses-uppercase-hex" as *u8, t_p2, ctr)
320 var t_p3: i64 = 0
321 if wa_is_pin("a7b5671e50ee3610ec3ad2e1278a33b2cb11339" as *u8) == 0 { t_p3 = 1 }
322 gv_check("neg-control-pin-refuses-39-hex" as *u8, t_p3, ctr)
323
324 // ---- THE NAME ALLOWLIST ---------------------------------------------------------------------
325 let nm_real: *u8 = "namednodemap-supported-property-names.html" as *u8
326 var t_n0: i64 = 0
327 if wa_is_safe_name(nm_real, wa_strlen(nm_real)) == 1 { t_n0 = 1 }
328 gv_check("safe-name-accepts-a-real-wpt-filename" as *u8, t_n0, ctr)
329 var t_n1: i64 = 0
330 if wa_is_safe_name(nm_esc, wa_strlen(nm_esc)) == 0 { t_n1 = 1 }
331 gv_check("neg-control-safe-name-refuses-parent-traversal" as *u8, t_n1, ctr)
332 let nm_sl: *u8 = "a/b.html" as *u8
333 var t_n2: i64 = 0
334 if wa_is_safe_name(nm_sl, wa_strlen(nm_sl)) == 0 { t_n2 = 1 }
335 gv_check("neg-control-safe-name-refuses-a-slash" as *u8, t_n2, ctr)
336 let nm_dot: *u8 = ".hidden.html" as *u8
337 var t_n3: i64 = 0
338 if wa_is_safe_name(nm_dot, wa_strlen(nm_dot)) == 0 { t_n3 = 1 }
339 gv_check("neg-control-safe-name-refuses-a-leading-dot" as *u8, t_n3, ctr)
340
341 // ---- THE MANIFEST PARSER --------------------------------------------------------------------
342 // Four records in GitHub's real field order: two .html files, one .md file, one directory whose
343 // name ends .html. The declared population is 2 -- the other two are skipped for two DIFFERENT
344 // reasons and each reason has its own counter.
345 let js: *u8 = sys_mmap(GT_JSON_CAP)
346 var jo: i64 = gt_ch(js, 0, 91)
347 jo = gt_ch(js, jo, 10)
348 jo = gt_rec(js, jo, "DOMTokenList-Iterable.html" as *u8, "4cf84b12a22d15cbc8fb76d174ee0cbb7693b63b" as *u8, 1204, "file" as *u8, 1)
349 jo = gt_rec(js, jo, nm_real, "0000000000000000000000000000000000000000" as *u8, 1114, "file" as *u8, 1)
350 jo = gt_rec(js, jo, "README.md" as *u8, "59c821a7daa465a852a1e9cba209af40de132d12" as *u8, 67, "file" as *u8, 1)
351 jo = gt_rec(js, jo, "subdir.html" as *u8, "1111111111111111111111111111111111111111" as *u8, 0, "dir" as *u8, 1)
352 jo = gt_ch(js, jo, 93)
353
354 let namebuf: *u8 = sys_mmap(65536)
355 let offs: *i64 = sys_mmap(1024) as *i64
356 let sizes: *i64 = sys_mmap(1024) as *i64
357 let shas: *u8 = sys_mmap(4096)
358 gt_zero(rep)
359 let cnt: i64 = wa_parse_manifest(js, jo, namebuf, 65536, offs, sizes, shas, 64, rep)
360 gv_puts(" parse: entries=" as *u8); gv_num(rep[WA_R_ENTRIES])
361 gv_puts(" declared=" as *u8); gv_num(cnt)
362 gv_puts(" skipped_nothtml=" as *u8); gv_num(rep[WA_R_SKIPPED_NOTHTML])
363 gv_puts(" skipped_notfile=" as *u8); gv_num(rep[WA_R_SKIPPED_NOTFILE]); gv_puts("\n" as *u8)
364 var t_m0: i64 = 0
365 if rep[WA_R_ENTRIES] == 4 { t_m0 = 1 }
366 gv_check("manifest-parse-saw-all-four-entries" as *u8, t_m0, ctr)
367 var t_m1: i64 = 0
368 if cnt == 2 { if rep[WA_R_DECLARED] == 2 { t_m1 = 1 } }
369 gv_check("manifest-parse-declares-2-html-files-of-4-entries" as *u8, t_m1, ctr)
370 var t_m2: i64 = 0
371 if rep[WA_R_SKIPPED_NOTHTML] == 1 { if rep[WA_R_SKIPPED_NOTFILE] == 1 { t_m2 = 1 } }
372 gv_check("manifest-parse-counts-the-two-skip-reasons-separately" as *u8, t_m2, ctr)
373 var t_m3: i64 = 0
374 if (rep[WA_R_DECLARED] + rep[WA_R_SKIPPED_NOTHTML] + rep[WA_R_SKIPPED_NOTFILE]) == rep[WA_R_ENTRIES] { t_m3 = 1 }
375 gv_check("manifest-parse-partition-sums-to-the-entry-count" as *u8, t_m3, ctr)
376
377 var t_m4: i64 = 0
378 if cnt == 2 {
379 let n0: *u8 = ((namebuf as i64) + offs[0]) as *u8
380 let n1: *u8 = ((namebuf as i64) + offs[1]) as *u8
381 if wa_find(n0, wa_strlen(n0), 0, "DOMTokenList-Iterable.html" as *u8) == 0 {
382 if wa_find(n1, wa_strlen(n1), 0, nm_real) == 0 { t_m4 = 1 }
383 }
384 }
385 // the filename in record 2 contains the letters n-a-m-e twice; a key needle without its quotes
386 // would split the record there and lose it.
387 gv_check("manifest-parse-not-confused-by-a-filename-containing-the-key" as *u8, t_m4, ctr)
388 var t_m5: i64 = 0
389 if cnt == 2 { if sizes[0] == 1204 { if sizes[1] == 1114 { t_m5 = 1 } } }
390 gv_check("manifest-parse-reads-the-declared-sizes" as *u8, t_m5, ctr)
391 var t_m6: i64 = 0
392 if cnt == 2 { if gt_hexeq(shas, "4cf84b12a22d15cbc8fb76d174ee0cbb7693b63b" as *u8) == 1 { t_m6 = 1 } }
393 gv_check("manifest-parse-reads-the-declared-blob-sha" as *u8, t_m6, ctr)
394
395 // A record missing one required field REFUSES the whole parse. A silently skipped row would be a
396 // smaller population, which reads as better news.
397 let js2: *u8 = sys_mmap(GT_JSON_CAP)
398 var j2: i64 = gt_ch(js2, 0, 91)
399 j2 = gt_rec(js2, j2, "ok.html" as *u8, "4cf84b12a22d15cbc8fb76d174ee0cbb7693b63b" as *u8, 10, "file" as *u8, 1)
400 j2 = gt_rec(js2, j2, "nosha.html" as *u8, "unused" as *u8, 10, "file" as *u8, 0)
401 j2 = gt_ch(js2, j2, 93)
402 gt_zero(rep)
403 var t_m7: i64 = 0
404 if wa_parse_manifest(js2, j2, namebuf, 65536, offs, sizes, shas, 64, rep) == WA_PARSE_MALFORMED { t_m7 = 1 }
405 gv_check("neg-control-a-record-missing-its-sha-refuses-the-whole-parse" as *u8, t_m7, ctr)
406 gt_zero(rep)
407 var t_m8: i64 = 0
408 if wa_parse_manifest(js, jo, namebuf, 65536, offs, sizes, shas, 1, rep) == WA_PARSE_OVERFLOW { t_m8 = 1 }
409 gv_check("neg-control-more-records-than-the-table-is-refused-not-capped" as *u8, t_m8, ctr)
410 gt_zero(rep)
411 var t_m9: i64 = 0
412 if wa_parse_manifest(js, jo, namebuf, 8, offs, sizes, shas, 64, rep) == WA_PARSE_NAMEBUF { t_m9 = 1 }
413 gv_check("neg-control-exhausted-name-storage-is-refused-not-capped" as *u8, t_m9, ctr)
414
415 // ---- THE COMPLETENESS CONJUNCTION -----------------------------------------------------------
416 gt_zero(rep)
417 var t_c0: i64 = 0
418 if wa_coverage_complete(rep) == 0 { t_c0 = 1 }
419 gv_check("neg-control-coverage-complete-is-false-on-the-empty-set" as *u8, t_c0, ctr)
420 rep[WA_R_DECLARED] = 5
421 rep[WA_R_LANDED] = 3
422 rep[WA_R_REUSED] = 2
423 var t_c1: i64 = 0
424 if wa_coverage_complete(rep) == 1 { t_c1 = 1 }
425 gv_check("coverage-complete-true-when-every-declared-file-is-present" as *u8, t_c1, ctr)
426 var t_c2: i64 = 0
427 if wa_report_sums(rep) == 1 { t_c2 = 1 }
428 gv_check("partition-sums-when-the-report-is-consistent" as *u8, t_c2, ctr)
429 rep[WA_R_REUSED] = 1
430 rep[WA_R_FAIL_SHA] = 1
431 var t_c3: i64 = 0
432 if wa_coverage_complete(rep) == 0 { t_c3 = 1 }
433 gv_check("neg-control-coverage-complete-false-when-one-file-failed" as *u8, t_c3, ctr)
434 rep[WA_R_FAIL_SHA] = 0
435 var t_c4: i64 = 0
436 if wa_report_sums(rep) == 0 { t_c4 = 1 }
437 gv_check("neg-control-partition-leaks-when-the-report-does-not-reconcile" as *u8, t_c4, ctr)
438
439 // ---- MANIFEST EMIT AND THE MARKER -----------------------------------------------------------
440 gt_zero(rep)
441 let cnt2: i64 = wa_parse_manifest(js, jo, namebuf, 65536, offs, sizes, shas, 64, rep)
442 rep[WA_R_LANDED] = cnt2
443 rep[WA_R_COVERAGE_COMPLETE] = 1
444 wa_manifest_write(GT_DIR, "dom/lists" as *u8, "a7b5671e50ee3610ec3ad2e1278a33b2cb11339c" as *u8,
445 namebuf, offs, sizes, shas, cnt2, rep)
446 lp[0] = 0
447 let mb: *u8 = sys_read_file(p_mf, lp)
448 var has_pin: i64 = 0
449 var last_is_verdict: i64 = 0
450 var mlen: i64 = 0
451 if (mb as i64) != 0 {
452 mlen = lp[0]
453 if wa_find(mb, mlen, 0, "a7b5671e50ee3610ec3ad2e1278a33b2cb11339c" as *u8) >= 0 { has_pin = 1 }
454 // the LAST line, taken by POSITION: step over the trailing newline, then back to the one before
455 var e: i64 = mlen - 1
456 if e >= 0 { if (mb[e] as i64) == 10 { e = e - 1 } }
457 var s2: i64 = e
458 var seeking: i64 = 1
459 while seeking == 1 {
460 if s2 <= 0 { seeking = 0 } else {
461 if (mb[s2-1] as i64) == 10 { seeking = 0 } else { s2 = s2 - 1 }
462 }
463 }
464 if wa_find(mb, mlen, s2, "verdict" as *u8) == s2 { last_is_verdict = 1 }
465 }
466 gv_puts(" manifest: bytes=" as *u8); gv_num(mlen)
467 gv_puts(" rows=" as *u8); gv_num(cnt2); gv_puts("\n" as *u8)
468 var t_e0: i64 = 0
469 if mlen > 0 { t_e0 = 1 }
470 gv_check("manifest-emit-produced-a-readable-file" as *u8, t_e0, ctr)
471 gv_check("manifest-emit-carries-the-commit-pin" as *u8, has_pin, ctr)
472 gv_check("manifest-emit-last-line-is-the-canonical-verdict" as *u8, last_is_verdict, ctr)
473
474 wa_marker_set(GT_DIR, 0, 5, 3)
475 let mk_written: i64 = gt_exists(p_mk)
476 wa_marker_set(GT_DIR, 1, 5, 5)
477 var mk_still: i64 = gt_exists(p_mk)
478 gv_bite("marker-is-written-when-incomplete-and-removed-when-complete" as *u8, mk_written, mk_still, ctr)
479
480 // ---- TEARDOWN (the next run must measure itself, not this one) ------------------------------
481 sys_unlinkat(p_ok)
482 sys_unlinkat(p_tr)
483 sys_unlinkat(p_bad)
484 sys_unlinkat(p_mf)
485 sys_unlinkat(p_mk)
486
487 return gv_verdict("nx_wpt_ingest_gate" as *u8, ctr,
488 "offline proof of the ingest core: manifest parse, dual verification against the declared size and the declared git blob sha, raw write, read-back compare, pin rule, name allowlist, completeness conjunction, manifest and marker emit. The transport is nx_https_fetch_follow's subject and is NOT proven here." as *u8)
489}