code wiki / _hdl_build / nx_office_import_sign_gate.nx
nx_office_import_sign_gate.nx source
↩ module page · 259 lines · 16131 B
1// nx_office_import_sign_gate.nx -- INDEPENDENT GATE for the office IMPORT (LP1) and SIGN-FROM-VERSION (LP4) rungs of
2// /compare/legalpractice. Drives the pure core nx_office_serve IN-PROCESS (of_handle, real HTTP bytes, no sockets)
3// against a FRESH fixture under /tmp/<gate>/<now_us> (never a production plane). Inherits nx_gate_verdict: one
4// gv_check per tooth, gv_bite for the consent gate (fires on no-consent, silent on consent), gv_verdict carries the
5// verdict in the EXIT CODE. Two import fixtures: a .docx the office itself wrote (mechanism) and a GENUINE Microsoft
6// Word document banked in knowledge/fetched (real-world producer: 25 parts, headers, footnotes, a 13-column table).
7// Runs the REAL format organs (_offc/nx_docx.elf) via fork+exec, so it runs from the nishihost root. license_tier: ORIGINAL
8import "nx_office_serve.nx"
9import "nx_gate_verdict.nx"
10
11const OG_SCRATCH: *u8 = "/tmp/nx_office_import_sign_gate"
12const OG_WORD_FIXTURE: *u8 = "knowledge/fetched/cmp_legalpractice_msword_fixture.docx"
13const OG_DIRMODE: i64 = 493
14const OG_OUTCAP: i64 = 1048576
15const OG_REQCAP: i64 = 2097152
16const OG_PATHCAP: i64 = 600
17const OG_SMALL: i64 = 256
18const OG_SZP: i64 = 16
19const OG_BOUNDARY: *u8 = "nxOfficeGateBoundary7f3a"
20const OG_DOCX_CT: *u8 = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
21const OG_SEED_SPEC: *u8 = "name=seed&kind=doc&spec=H+Seed+Title%0AP+A+paragraph+of+body+text.%0AT+a%7Cb%7Cc%0AT+1%7C2%7C3"
22const OG_WORD_MIN_LINES: i64 = 10
23
24func og_path(out: *u8, root: *u8, tail: *u8) -> i64 {
25 var o: i64 = of_cat(out, 0, root)
26 o = of_cat(out, o, tail)
27 out[o] = 0 as u8
28 return o
29}
30// urlencoded POST through of_handle; returns response length
31func og_post(root: *u8, base: *u8, path: *u8, body: *u8, req: *u8, out: *u8) -> i64 {
32 var ro: i64 = of_cat(req, 0, "POST " as *u8)
33 ro = of_cat(req, ro, path)
34 ro = of_cat(req, ro, " HTTP/1.1\r\nHost: office.local\r\nContent-Length: " as *u8)
35 ro = of_catn(req, ro, of_slen(body))
36 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
37 ro = of_cat(req, ro, body)
38 return of_handle(root, base, req, ro, out, OG_OUTCAP)
39}
40func og_get(root: *u8, base: *u8, path: *u8, req: *u8, out: *u8) -> i64 {
41 var ro: i64 = of_cat(req, 0, "GET " as *u8)
42 ro = of_cat(req, ro, path)
43 ro = of_cat(req, ro, " HTTP/1.1\r\nHost: office.local\r\n\r\n" as *u8)
44 return of_handle(root, base, req, ro, out, OG_OUTCAP)
45}
46// multipart/form-data POST /import: optional name part, then the file part (filename + raw bytes). withfile=0 omits
47// the file part entirely (the "no file part" negative).
48func og_import(root: *u8, base: *u8, name: *u8, filename: *u8, bytes: *u8, n: i64, withfile: i64, req: *u8, body: *u8, out: *u8) -> i64 {
49 var bo: i64 = 0
50 if name[0] != (0 as u8) {
51 bo = of_cat(body, bo, "--" as *u8); bo = of_cat(body, bo, OG_BOUNDARY)
52 bo = of_cat(body, bo, "\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n" as *u8)
53 bo = of_cat(body, bo, name); bo = of_cat(body, bo, "\r\n" as *u8)
54 }
55 if withfile == 1 {
56 bo = of_cat(body, bo, "--" as *u8); bo = of_cat(body, bo, OG_BOUNDARY)
57 bo = of_cat(body, bo, "\r\nContent-Disposition: form-data; name=\"file\"; filename=\"" as *u8)
58 bo = of_cat(body, bo, filename)
59 bo = of_cat(body, bo, "\"\r\nContent-Type: application/octet-stream\r\n\r\n" as *u8)
60 var i: i64 = 0
61 while i < n { body[bo] = bytes[i]; bo = bo + 1; i = i + 1 }
62 bo = of_cat(body, bo, "\r\n" as *u8)
63 }
64 bo = of_cat(body, bo, "--" as *u8); bo = of_cat(body, bo, OG_BOUNDARY); bo = of_cat(body, bo, "--\r\n" as *u8)
65 var ro: i64 = of_cat(req, 0, "POST /import HTTP/1.1\r\nHost: office.local\r\nContent-Type: multipart/form-data; boundary=" as *u8)
66 ro = of_cat(req, ro, OG_BOUNDARY)
67 ro = of_cat(req, ro, "\r\nContent-Length: " as *u8)
68 ro = of_catn(req, ro, bo)
69 ro = of_cat(req, ro, "\r\n\r\n" as *u8)
70 var k: i64 = 0
71 while k < bo { req[ro] = body[k]; ro = ro + 1; k = k + 1 }
72 return of_handle(root, base, req, ro, out, OG_OUTCAP)
73}
74// the HTTP status token of a response is the first line: "HTTP/1.1 <code> ..."
75func og_status_is(out: *u8, n: i64, code: *u8) -> i64 {
76 if n < 12 { return 0 }
77 return of_memhas(out, 13, code)
78}
79// offset of the body (after CRLFCRLF), -1 if none
80func og_body_off(out: *u8, n: i64) -> i64 {
81 var i: i64 = 0
82 while i + 3 < n {
83 if out[i] == (13 as u8) { if out[i+1] == (10 as u8) { if out[i+2] == (13 as u8) { if out[i+3] == (10 as u8) { return i + 4 } } } }
84 i = i + 1
85 }
86 return 0 - 1
87}
88func og_same(a: *u8, an: i64, b: *u8, bn: i64) -> i64 {
89 if an != bn { return 0 }
90 if an <= 0 { return 0 }
91 var i: i64 = 0
92 while i < an { if a[i] != b[i] { return 0 } i = i + 1 }
93 return 1
94}
95func og_count_lines(buf: *u8, n: i64) -> i64 {
96 var c: i64 = 0
97 var i: i64 = 0
98 while i < n { if buf[i] == (10 as u8) { c = c + 1 } i = i + 1 }
99 return c
100}
101// read a whole file into a fresh map; returns length (-1 absent); caller frees with sys_free_file
102func og_read(path: *u8, outp: *i64) -> i64 {
103 let szp: *i64 = sys_mmap(OG_SZP) as *i64
104 szp[0] = 0
105 let b: *u8 = sys_read_file(path, szp)
106 outp[0] = b as i64
107 if (b as i64) == 0 { sys_munmap(szp as *u8, OG_SZP); return 0 - 1 }
108 let n: i64 = szp[0]
109 sys_munmap(szp as *u8, OG_SZP)
110 return n
111}
112// "key=value" line value (NUL-terminated copy into out); 0 if absent
113func og_field(buf: *u8, n: i64, key: *u8, out: *u8, cap: i64) -> i64 {
114 let kl: i64 = of_slen(key)
115 var i: i64 = 0
116 while i + kl <= n {
117 var at_line: i64 = 0
118 if i == 0 { at_line = 1 } else { if buf[i - 1] == (10 as u8) { at_line = 1 } }
119 if at_line == 1 { if of_memhas((buf as i64 + i) as *u8, kl, key) == 1 {
120 var q: i64 = i + kl
121 var o: i64 = 0
122 while q < n { if buf[q] == (10 as u8) { q = n } else { if o < cap - 1 { out[o] = buf[q]; o = o + 1 } q = q + 1 } }
123 out[o] = 0 as u8
124 return o
125 } }
126 i = i + 1
127 }
128 out[0] = 0 as u8
129 return 0
130}
131
132func main() -> i64 {
133 gv_head("NX-OFFICE-IMPORT-SIGN-GATE -- LP1 import (.docx in, original kept byte for byte, paragraph-faithful spec) + LP4 sign-from-version (UETA consent gate, hash-chained audit, sealed certificate) over the pure core, fixture under /tmp" as *u8)
134 let ctr: *i64 = gv_ctr()
135 sys_mkdir(OG_SCRATCH, OG_DIRMODE)
136 let root: *u8 = sys_mmap(OG_SMALL)
137 var ro: i64 = of_cat(root, 0, OG_SCRATCH)
138 ro = of_cat(root, ro, "/" as *u8)
139 ro = of_catn(root, ro, sys_now_us())
140 root[ro] = 0 as u8
141 let base: *u8 = sys_mmap(4)
142 base[0] = 0 as u8
143 let req: *u8 = sys_mmap(OG_REQCAP)
144 let body: *u8 = sys_mmap(OG_REQCAP)
145 let out: *u8 = sys_mmap(OG_OUTCAP)
146 let pth: *u8 = sys_mmap(OG_PATHCAP)
147 let bp: *i64 = sys_mmap(OG_SZP) as *i64
148 gv_puts(" fixture root: " as *u8); gv_puts(root); gv_puts("\n" as *u8)
149
150 // ---- seed: the office writes a real .docx (the mechanism fixture) ----
151 var n: i64 = og_post(root, base, "/save" as *u8, OG_SEED_SPEC, req, out)
152 gv_check("seed-doc-created-by-the-office-itself" as *u8, og_status_is(out, n, "303" as *u8), ctr)
153 og_path(pth, root, "/seed/v1/file.docx" as *u8)
154 let seedn: i64 = og_read(pth, bp)
155 let seed: *u8 = bp[0] as *u8
156 gv_puts(" seed docx bytes=" as *u8); gv_num(seedn); gv_puts("\n" as *u8)
157 var seedzip: i64 = 0
158 if seedn > 4 { if seed[0] == (80 as u8) { if seed[1] == (75 as u8) { seedzip = 1 } } }
159 gv_check("seed-docx-is-a-zip-package" as *u8, seedzip, ctr)
160
161 // ---- T: import the seed as a NEW document ----
162 n = og_import(root, base, "imported" as *u8, "seed.docx" as *u8, seed, seedn, 1, req, body, out)
163 gv_check("import-docx-answers-303-to-the-new-document" as *u8, ((og_status_is(out, n, "303" as *u8)) as i64) & ((of_memhas(out, n, "Location: /doc/imported" as *u8)) as i64), ctr)
164 og_path(pth, root, "/imported/v1/original.docx" as *u8)
165 let on: i64 = og_read(pth, bp)
166 let orig: *u8 = bp[0] as *u8
167 gv_check("original-kept-byte-for-byte-as-v1" as *u8, og_same(orig, on, seed, seedn), ctr)
168 n = og_get(root, base, "/original/imported/v1" as *u8, req, out)
169 let bo1: i64 = og_body_off(out, n)
170 var served_same: i64 = 0
171 if bo1 > 0 { served_same = og_same((out as i64 + bo1) as *u8, n - bo1, seed, seedn) }
172 gv_check("original-route-serves-the-untouched-upload-with-docx-content-type" as *u8, (served_same) & ((of_memhas(out, bo1, OG_DOCX_CT)) as i64), ctr)
173 og_path(pth, root, "/imported/v1/spec.txt" as *u8)
174 let sn: i64 = og_read(pth, bp)
175 let spec: *u8 = bp[0] as *u8
176 gv_puts(" imported spec lines=" as *u8); gv_num(og_count_lines(spec, sn)); gv_puts("\n" as *u8)
177 gv_check("spec-is-paragraph-faithful-heading-paragraph-and-table-rows" as *u8, ((of_memhas(spec, sn, "H Seed Title" as *u8)) as i64) & ((of_memhas(spec, sn, "P A paragraph of body text." as *u8)) as i64) & ((of_memhas(spec, sn, "T a|b|c" as *u8)) as i64) & ((of_memhas(spec, sn, "T 1|2|3" as *u8)) as i64), ctr)
178 og_path(pth, root, "/imported/manifest.txt" as *u8)
179 let mn: i64 = og_read(pth, bp)
180 let man: *u8 = bp[0] as *u8
181 gv_check("manifest-row-marks-v1-as-import" as *u8, of_memhas(man, mn, "import" as *u8), ctr)
182 n = og_get(root, base, "/doc/imported" as *u8, req, out)
183 gv_check("doc-page-opens-the-import-in-the-editor-with-its-spec" as *u8, ((og_status_is(out, n, "200" as *u8)) as i64) & ((of_memhas(out, n, "H Seed Title" as *u8)) as i64) & ((of_memhas(out, n, "<th>Sign</th>" as *u8)) as i64), ctr)
184 // negatives, each naming WHICH refusal fired
185 n = og_import(root, base, "imported" as *u8, "seed.docx" as *u8, seed, seedn, 1, req, body, out)
186 gv_check("neg-control-duplicate-name-refused-409-import-never-appends" as *u8, og_status_is(out, n, "409" as *u8), ctr)
187 n = og_import(root, base, "nota" as *u8, "nota.docx" as *u8, "this is not a zip package" as *u8, 25, 1, req, body, out)
188 gv_check("neg-control-non-package-bytes-refused-415" as *u8, og_status_is(out, n, "415" as *u8), ctr)
189 n = og_import(root, base, "nofile" as *u8, "x.docx" as *u8, seed, seedn, 0, req, body, out)
190 gv_check("neg-control-missing-file-part-refused-400" as *u8, og_status_is(out, n, "400" as *u8), ctr)
191 n = og_import(root, base, "" as *u8, "My Draft Letter.docx" as *u8, seed, seedn, 1, req, body, out)
192 gv_check("blank-name-derives-my-draft-letter-from-the-filename" as *u8, ((og_status_is(out, n, "303" as *u8)) as i64) & ((of_memhas(out, n, "Location: /doc/my-draft-letter" as *u8)) as i64), ctr)
193
194 // ---- the GENUINE Microsoft Word document (real-world producer) ----
195 let wn: i64 = og_read(OG_WORD_FIXTURE, bp)
196 let word: *u8 = bp[0] as *u8
197 if gv_need("real-word-fixture knowledge/fetched/cmp_legalpractice_msword_fixture.docx" as *u8, (wn > 0) as i64, ctr) == 1 {
198 gv_puts(" word fixture bytes=" as *u8); gv_num(wn); gv_puts("\n" as *u8)
199 n = og_import(root, base, "msword" as *u8, "Real Word Agreement.docx" as *u8, word, wn, 1, req, body, out)
200 gv_check("real-word-docx-imports-303" as *u8, og_status_is(out, n, "303" as *u8), ctr)
201 og_path(pth, root, "/msword/v1/original.docx" as *u8)
202 let won: i64 = og_read(pth, bp)
203 gv_check("real-word-original-kept-byte-for-byte" as *u8, og_same(bp[0] as *u8, won, word, wn), ctr)
204 og_path(pth, root, "/msword/v1/spec.txt" as *u8)
205 let wsn: i64 = og_read(pth, bp)
206 let wspec: *u8 = bp[0] as *u8
207 let wlines: i64 = og_count_lines(wspec, wsn)
208 gv_puts(" word spec lines=" as *u8); gv_num(wlines); gv_puts(" bytes=" as *u8); gv_num(wsn); gv_puts("\n" as *u8)
209 gv_check("real-word-spec-has-table-rows-and-paragraphs-at-least-10-lines" as *u8, ((wlines >= OG_WORD_MIN_LINES) as i64) & ((of_memhas(wspec, wsn, "T " as *u8)) as i64) & ((of_memhas(wspec, wsn, "P " as *u8)) as i64), ctr)
210 gv_check("real-word-spec-keeps-utf8-punctuation-intact" as *u8, (of_memhas(wspec, wsn, "VVUQ 1 – Verification" as *u8)) as i64, ctr)
211 }
212
213 // ---- LP4: sign-from-version over the imported document ----
214 n = og_post(root, base, "/sign" as *u8, "name=imported&version=1&signer=alice" as *u8, req, out)
215 let noconsent_403: i64 = og_status_is(out, n, "403" as *u8)
216 og_path(pth, root, "/imported/v1/cert.txt" as *u8)
217 let c0: i64 = og_read(pth, bp)
218 gv_check("neg-control-no-consent-refused-403-and-no-certificate-written" as *u8, (noconsent_403) & ((c0 < 0) as i64), ctr)
219 n = og_post(root, base, "/sign" as *u8, "name=imported&version=1&signer=alice&consent=yes" as *u8, req, out)
220 let consent_303: i64 = og_status_is(out, n, "303" as *u8)
221 let consent_403: i64 = og_status_is(out, n, "403" as *u8)
222 gv_check("consent-yes-signs-and-answers-303-back-to-the-document" as *u8, consent_303, ctr)
223 gv_bite("ueta-consent-gate" as *u8, noconsent_403, consent_403, ctr)
224 let c1: i64 = og_read(pth, bp)
225 let cert: *u8 = bp[0] as *u8
226 let fld: *u8 = sys_mmap(OG_SMALL)
227 og_field(cert, c1, "document=" as *u8, fld, OG_SMALL)
228 og_path(pth, root, "/imported/v1/file.docx" as *u8)
229 let szb: *i64 = sys_mmap(OG_SZP) as *i64
230 let doccid: *u8 = sys_mmap(OG_SMALL)
231 cid_of_file(pth, szb, doccid)
232 gv_puts(" cert document=" as *u8); gv_puts(fld); gv_puts(" file cid=" as *u8); gv_puts(doccid); gv_puts("\n" as *u8)
233 gv_check("certificate-binds-the-document-cid-of-the-signed-version" as *u8, ((c1 > 0) as i64) & ((of_seq(fld, doccid)) as i64), ctr)
234 gv_check("certificate-records-completed-with-one-signer" as *u8, ((of_memhas(cert, c1, "status=completed" as *u8)) as i64) & ((of_memhas(cert, c1, "signers=1" as *u8)) as i64) & ((of_memhas(cert, c1, "certificate=nxc1-" as *u8)) as i64), ctr)
235 let head1: *u8 = sys_mmap(OG_SMALL)
236 og_field(cert, c1, "audit_head=" as *u8, head1, OG_SMALL)
237 og_path(pth, root, "/imported/sign-manifest.txt" as *u8)
238 let smn: i64 = og_read(pth, bp)
239 gv_check("certificate-retained-in-the-immutable-sign-store" as *u8, (smn > 0) as i64, ctr)
240 n = og_get(root, base, "/cert/imported/v1" as *u8, req, out)
241 gv_check("cert-route-serves-the-receipt-as-text" as *u8, ((og_status_is(out, n, "200" as *u8)) as i64) & ((of_memhas(out, n, "certificate=nxc1-" as *u8)) as i64) & ((of_memhas(out, n, "text/plain" as *u8)) as i64), ctr)
242 n = og_get(root, base, "/doc/imported" as *u8, req, out)
243 gv_check("doc-page-shows-signed-receipt-link-on-the-signed-version" as *u8, of_memhas(out, n, "signed · receipt" as *u8), ctr)
244 n = og_post(root, base, "/sign" as *u8, "name=imported&version=1&signer=bob&consent=yes" as *u8, req, out)
245 og_path(pth, root, "/imported/v1/cert.txt" as *u8)
246 let c2: i64 = og_read(pth, bp)
247 let cert2: *u8 = bp[0] as *u8
248 let head2: *u8 = sys_mmap(OG_SMALL)
249 og_field(cert2, c2, "audit_head=" as *u8, head2, OG_SMALL)
250 gv_puts(" audit head 1=" as *u8); gv_puts(head1); gv_puts("\n audit head 2=" as *u8); gv_puts(head2); gv_puts("\n" as *u8)
251 gv_check("second-signer-chains-signers-2-and-advances-the-audit-head" as *u8, ((og_status_is(out, n, "303" as *u8)) as i64) & ((of_memhas(cert2, c2, "signers=2" as *u8)) as i64) & (((of_seq(head1, head2)) == 0) as i64) & ((of_slen(head2) == OF_HEXSZ) as i64), ctr)
252 n = og_post(root, base, "/sign" as *u8, "name=imported&version=1&signer=a%20b&consent=yes" as *u8, req, out)
253 gv_check("neg-control-signer-with-a-space-refused-400" as *u8, og_status_is(out, n, "400" as *u8), ctr)
254 n = og_post(root, base, "/sign" as *u8, "name=imported&version=9&signer=alice&consent=yes" as *u8, req, out)
255 gv_check("neg-control-unknown-version-refused-404" as *u8, og_status_is(out, n, "404" as *u8), ctr)
256 n = og_get(root, base, "/cert/seed/v1" as *u8, req, out)
257 gv_check("neg-control-unsigned-version-has-no-receipt-404" as *u8, og_status_is(out, n, "404" as *u8), ctr)
258 return gv_verdict("OFFICE-IMPORT-SIGN-GATE" as *u8, ctr, "LP1 import + LP4 sign over the pure core against a /tmp fixture; a genuine Word document is the real-world producer" as *u8)
259}