code wiki / _hdl_build / nx_legal_blob_gate.nx
nx_legal_blob_gate.nx source
↩ module page · 134 lines · 5748 B
1// nx_legal_blob_gate.nx -- GATE for doc-blob persistence (ls_blob_save/load), ENGINEER verify.
2//
3// Completes the durability story: the actual document BYTES survive a restart (the
4// workflow state already did via D7/D8; the blob is the doc itself). Composes
5// nx_legal_store (blob save/load) + nx_doc_serve (serve byte-exact), each w/ a control:
6// T1 ROUND-TRIP : a blob with adversarial bytes (CRLFCRLF + NUL) reloads byte-exact
7// T2 SERVE BYTE-EXACT: serving the RELOADED blob via nx_doc_serve round-trips bit-for-bit
8// (the served document == the persisted bytes == what was sealed)
9// T3 TENANT ISOLATION: another tenant's blob path is a different file -> absent; bad tenant rejected
10// T4 ABSENT + CORRUPT: missing -> -1 ; wrong-magic -> -MAGIC (never silent garbage)
11// T5 LARGE BLOB : a 1000-byte doc round-trips exactly (not just tiny)
12//
13// nx_legal_store's record save/load is UNCHANGED (blob funcs are additive) -> no regression.
14// Evidence -> knowledge/status/legal_blob.log
15// license_tier: ORIGINAL
16import "nx_legal_store.nx"
17import "nx_doc_serve.nx"
18import "nx_doc_vault.nx"
19import "nx_syscalls.nx"
20import "nx_gate_verdict.nx"
21
22const LBLOB_LOG: *u8 = "knowledge/status/legal_blob.log"
23const LBLOB_BASE: *u8 = "/tmp/nx_blob_"
24
25func ew(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 }
26func ewn(fd: i64, v: i64) -> i64 {
27 let bb: *u8 = sys_mmap(28); var m: i64 = v
28 if m < 0 { m = 0 - m; sys_write(fd, "-" as *u8, 1) }
29 let t: *u8 = sys_mmap(28); var k: i64 = 0
30 if m == 0 { t[0] = 48; k = 1 }
31 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
32 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
33 sys_write(fd, bb, k); return 0
34}
35
36func main() -> i64 {
37 var ok: i64 = 1
38 let p: *u8 = sys_mmap(512)
39 let pB: *u8 = sys_mmap(512)
40
41 // a document blob with adversarial bytes (CRLFCRLF + NUL inside)
42 let doc: *u8 = sys_mmap(64)
43 doc[0]=37; doc[1]=80; doc[2]=68; doc[3]=70; doc[4]=13; doc[5]=10; doc[6]=13; doc[7]=10; doc[8]=0; doc[9]=88; doc[10]=89
44 let dlen: i64 = 11
45
46 // ---- T1: blob round-trip ----
47 var t1: i64 = 1
48 if ls_path(p, LBLOB_BASE, "clientA" as *u8, "8601.blob" as *u8) < 0 { t1 = 0 }
49 if ls_blob_save(doc, dlen, p) != LS_OK { t1 = 0 }
50 let rbuf: *u8 = sys_mmap(64)
51 let ll: i64 = ls_blob_load(rbuf, 64, p)
52 if ll != dlen { t1 = 0 }
53 var i: i64 = 0
54 while i < dlen {
55 if rbuf[i] != doc[i] { t1 = 0 }
56 i = i + 1
57 }
58 if t1 != 1 { ok = 0 }
59
60 // ---- T2: serve the RELOADED blob byte-exact (compose D3) ----
61 var t2: i64 = 1
62 let resp: *u8 = sys_mmap(4096)
63 let rn: i64 = nx_doc_serve_response(resp, rbuf, ll, DF_PDF, DISP_INLINE, "doc" as *u8)
64 if nx_doc_serve_roundtrip_ok(resp, rn, doc, dlen) != 1 { t2 = 0 }
65 if t2 != 1 { ok = 0 }
66
67 // ---- T3: tenant isolation ----
68 var t3: i64 = 1
69 if ls_path(pB, LBLOB_BASE, "clientB" as *u8, "8601.blob" as *u8) < 0 { t3 = 0 }
70 if ls_blob_load(rbuf, 64, pB) != (0 - 1) { t3 = 0 } // clientB has no such blob
71 if ls_path(p, LBLOB_BASE, "../x" as *u8, "8601.blob" as *u8) != (0 - 1) { t3 = 0 }
72 if t3 != 1 { ok = 0 }
73
74 // ---- T4: absent + corrupt ----
75 var t4: i64 = 1
76 let pmiss: *u8 = sys_mmap(512)
77 if ls_path(pmiss, LBLOB_BASE, "nobody" as *u8, "x.blob" as *u8) < 0 { t4 = 0 }
78 if ls_blob_load(rbuf, 64, pmiss) != (0 - 1) { t4 = 0 }
79 let pbad: *u8 = sys_mmap(512)
80 if ls_path(pbad, LBLOB_BASE, "corrupt" as *u8, "x.blob" as *u8) < 0 { t4 = 0 }
81 let bfd: i64 = sys_openat_wr(pbad, 420)
82 if bfd < 0 { t4 = 0 } else {
83 let bh: *i64 = sys_mmap(32) as *i64
84 bh[0] = 0xDEADBEEF; bh[1] = 4
85 sys_write(bfd, bh as *u8, 16)
86 sys_close(bfd)
87 }
88 if ls_blob_load(rbuf, 64, pbad) != (0 - LS_ERR_MAGIC) { t4 = 0 }
89 if t4 != 1 { ok = 0 }
90
91 // ---- T5: a large (1000-byte) blob round-trips ----
92 var t5: i64 = 1
93 let big: *u8 = sys_mmap(2048)
94 var bi: i64 = 0
95 while bi < 1000 { big[bi] = ((bi * 31 + 7) & 0xff) as u8; bi = bi + 1 }
96 if ls_path(p, LBLOB_BASE, "clientA" as *u8, "big.blob" as *u8) < 0 { t5 = 0 }
97 if ls_blob_save(big, 1000, p) != LS_OK { t5 = 0 }
98 let rbig: *u8 = sys_mmap(2048)
99 let bl: i64 = ls_blob_load(rbig, 2048, p)
100 if bl != 1000 { t5 = 0 }
101 var bj: i64 = 0
102 while bj < 1000 {
103 if rbig[bj] != big[bj] { t5 = 0 }
104 bj = bj + 1
105 }
106 if t5 != 1 { ok = 0 }
107
108 // ---- evidence ----
109 var fd: i64 = 1
110 while fd >= 1 {
111 ew(fd, "LEGALBLOBGATE authored=organ composes=D3 blob_roundtrip=" as *u8); ewn(fd, t1)
112 ew(fd, " serve_byteexact=" as *u8); ewn(fd, t2)
113 ew(fd, " tenant_isolation=" as *u8); ewn(fd, t3)
114 ew(fd, " absent_corrupt=" as *u8); ewn(fd, t4)
115 ew(fd, " large_blob=" as *u8); ewn(fd, t5)
116 if ok == 1 { ew(fd, " verdict=GREEN\n" as *u8) } else { ew(fd, " verdict=RED\n" as *u8) }
117 if fd == 1 {
118 let lf: i64 = sys_openat_append(LBLOB_LOG, 420)
119 if lf >= 1 { fd = lf } else { fd = 0 }
120 } else {
121 sys_close(fd); fd = 0
122 }
123 }
124
125 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
126 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
127 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
128 let ctr__dry: *i64 = gv_ctr()
129 ctr__dry[0] = ok
130 ctr__dry[1] = 1
131 let rc__dry: i64 = gv_verdict("LEGAL-BLOB-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
132 sys_exit(rc__dry)
133 return rc__dry
134}