code wiki / _hdl_build / nx_wiki_publish_guard_gate.nx
nx_wiki_publish_guard_gate.nx source
↩ module page · 157 lines · 8982 B
1// nx_wiki_publish_guard_gate.nx -- TEETH for the pre-publish guard (nx_wiki_publish_guard). Proves the
2// fail-closed "liar-kill": a page is ALLOWED only when it is fresh-stamped AND every [[cite:<cid>]]
3// resolves in the content-addressed archive AND every internal /wiki/<x>.html link is in the corpus
4// AND the body is real content. Positive control (well-formed page -> ALLOW) + FOUR negative controls,
5// each asserting the EXACT machine-readable reason code (not merely "rejected"):
6// (i) well-formed page -> PG_ALLOW
7// (ii) no freshness stamp -> PG_REJECT_NO_FRESHNESS
8// (iii) a dangling [[cite:<cid>]] (cid absent) -> PG_REJECT_DANGLING_CITE
9// (iv) href to a /wiki page NOT in the corpus -> PG_REJECT_DEAD_LINK
10// (v) empty / placeholder body -> PG_REJECT_PLACEHOLDER
11// The positive control PLANTS a real resolvable citation: it archives a source body into a fresh
12// per-run seg_store (ss_begin -> war_archive_page -> ss_commit), gets back the REAL cid, and embeds
13// [[cite:<that cid>]] in the page -- so the guard's archive resolution is exercised end-to-end, not
14// mocked. Appends "PUBGUARD ... verdict=PASS" to knowledge/status/pubguard_gate.log on all-pass.
15// Exit 0 iff all pass (no fake-green). license_tier: ORIGINAL
16import "nx_wiki_publish_guard.nx"
17import "nx_syscalls.nx"
18
19func g_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
20func g_num(v: i64) -> i64 {
21 let bb: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m }
22 let t: *u8 = sys_mmap(28); var k: i64 = 0
23 if m == 0 { t[0] = 48 as u8; k = 1 }
24 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
25 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
26 sys_write(1, bb, k); return 0
27}
28func g_cat(dst: *u8, off: i64, s: *u8) -> i64 { var o: i64 = off; var k: i64 = 0; while s[k] != (0 as u8) { dst[o] = s[k]; o = o + 1; k = k + 1 } return o }
29func g_catnum(dst: *u8, off: i64, v: i64) -> i64 {
30 var o: i64 = off; let t: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m }
31 var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 }
32 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
33 var i: i64 = 0; while i < k { dst[o] = t[k - 1 - i]; o = o + 1; i = i + 1 } return o
34}
35func g_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
36
37// name a reject code for the human-readable row (keeps the assertion legible).
38func g_codename(v: i64) -> *u8 {
39 if v == PG_ALLOW { return "ALLOW" as *u8 }
40 if v == PG_REJECT_NO_FRESHNESS { return "REJECT NO_FRESHNESS" as *u8 }
41 if v == PG_REJECT_DANGLING_CITE { return "REJECT DANGLING_CITE" as *u8 }
42 if v == PG_REJECT_DEAD_LINK { return "REJECT DEAD_LINK" as *u8 }
43 if v == PG_REJECT_PLACEHOLDER { return "REJECT PLACEHOLDER" as *u8 }
44 return "UNKNOWN" as *u8
45}
46
47// emit one gate row: got vs want (the EXACT code). pass iff got==want.
48func g_row(id: i64, got: i64, want: i64, what: *u8) -> i64 {
49 var ok: i64 = 0
50 if got == want { ok = 1 }
51 g_w("PGROW " as *u8); g_num(id); g_w(" " as *u8)
52 if ok == 1 { g_w("PASS " as *u8) } else { g_w("FAIL " as *u8) }
53 g_w(what); g_w(" [want=" as *u8); g_w(g_codename(want)); g_w(" got=" as *u8); g_w(g_codename(got)); g_w("]\n" as *u8)
54 return ok
55}
56
57func main() -> i64 {
58 // ---- a fresh per-run archive store prefix (flat files in /tmp; no mkdir needed) ----
59 let prefix: *u8 = sys_mmap(128)
60 var po: i64 = 0
61 po = ss_cat(prefix, po, "/tmp/pgds" as *u8)
62 po = ss_catn(prefix, po, sys_now_us())
63 po = ss_cat(prefix, po, "-" as *u8)
64 prefix[po] = 0 as u8
65
66 // ---- PLANT a real resolvable source: archive a body, get back its REAL cid ----
67 let srcbody: *u8 = "NIST SP 800-207: a zero-trust architecture denies by default." as *u8
68 let srcn: i64 = g_slen(srcbody)
69 let goodcid: *u8 = sys_mmap(80)
70 let w: *i64 = ss_begin()
71 let ar: i64 = war_archive_page(w, "src_ztna" as *u8, srcbody, srcn, goodcid)
72 if ar != 0 { g_w("PGGATE FATAL: archive add failed\n" as *u8); sys_exit(2); return 2 }
73 let cr: i64 = ss_commit(prefix, w, 1)
74 if cr != 0 { g_w("PGGATE FATAL: archive commit failed\n" as *u8); sys_exit(2); return 2 }
75 // sanity: the cid must now resolve (proves the fixture before we test the guard)
76 let pp: *i64 = sys_mmap(16) as *i64
77 let chk: i64 = war_get_by_cid(prefix, goodcid, pp, PG_SCAN_CAP)
78 if chk <= 0 { g_w("PGGATE FATAL: planted cid did not resolve\n" as *u8); sys_exit(2); return 2 }
79
80 // ---- corpus set: the slugs that will be published together ----
81 let cs_ptr: *i64 = sys_mmap(8 * 8) as *i64
82 let cs_len: *i64 = sys_mmap(8 * 8) as *i64
83 cs_ptr[0] = "start" as *u8 as i64; cs_len[0] = 5
84 cs_ptr[1] = "charter" as *u8 as i64; cs_len[1] = 7
85 cs_ptr[2] = "nist_stem" as *u8 as i64; cs_len[2] = 9
86 let ncorpus: i64 = 3
87
88 // ---- build the WELL-FORMED page: freshness + a RESOLVABLE cite + only corpus links + real body --
89 // page = "...epoch=123... [[cite:<goodcid>]] ... <a href=\"/wiki/charter.html\">...\""
90 let good: *u8 = sys_mmap(4096)
91 var go: i64 = 0
92 go = g_cat(good, go, "<h1>Zero Trust</h1><p class=\"fresh\">epoch=1781730256</p>" as *u8)
93 go = g_cat(good, go, "<p>See <a href=\"/wiki/charter.html\">the charter</a> and " as *u8)
94 go = g_cat(good, go, "<a href=\"/wiki/start.html#tasks\">tasks</a>.</p>" as *u8)
95 go = g_cat(good, go, "<p>Evidence: [[cite:" as *u8)
96 go = g_cat(good, go, goodcid) // the REAL resolvable cid
97 go = g_cat(good, go, "]]</p>" as *u8)
98 let goodn: i64 = go
99
100 var pass: i64 = 0
101 var rows: i64 = 0
102 var v: i64 = 0
103
104 // (i) POSITIVE CONTROL: well-formed page -> ALLOW
105 v = pg_decide(prefix, good, goodn, cs_ptr, cs_len, ncorpus)
106 rows = rows + 1; pass = pass + g_row(0, v, PG_ALLOW, "well-formed page (fresh+resolvable-cite+live-links+real-body)" as *u8)
107
108 // (ii) NO FRESHNESS: same content shape but no epoch= stamp -> REJECT NO_FRESHNESS
109 let nofresh: *u8 = sys_mmap(2048)
110 var nf: i64 = 0
111 nf = g_cat(nofresh, nf, "<h1>Zero Trust</h1><p>no stamp here</p>" as *u8)
112 nf = g_cat(nofresh, nf, "<p>See <a href=\"/wiki/charter.html\">charter</a>.</p>" as *u8)
113 let nofreshn: i64 = nf
114 v = pg_decide(prefix, nofresh, nofreshn, cs_ptr, cs_len, ncorpus)
115 rows = rows + 1; pass = pass + g_row(1, v, PG_REJECT_NO_FRESHNESS, "page missing freshness stamp" as *u8)
116
117 // (iii) DANGLING CITE: fresh + a cite whose cid is NOT in the archive -> REJECT DANGLING_CITE
118 let dang: *u8 = sys_mmap(2048)
119 var dg: i64 = 0
120 dg = g_cat(dang, dg, "<h1>Zero Trust</h1><p>epoch=1781730256</p>" as *u8)
121 dg = g_cat(dang, dg, "<p>Evidence: [[cite:nxc1-deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef]]</p>" as *u8)
122 let dangn: i64 = dg
123 v = pg_decide(prefix, dang, dangn, cs_ptr, cs_len, ncorpus)
124 rows = rows + 1; pass = pass + g_row(2, v, PG_REJECT_DANGLING_CITE, "page with a dangling (unresolvable) cite" as *u8)
125
126 // (iv) DEAD LINK: fresh + an href to a /wiki page NOT in the corpus -> REJECT DEAD_LINK
127 let dead: *u8 = sys_mmap(2048)
128 var dd: i64 = 0
129 dd = g_cat(dead, dd, "<h1>Zero Trust</h1><p>epoch=1781730256</p>" as *u8)
130 dd = g_cat(dead, dd, "<p>See <a href=\"/wiki/ghost_page.html\">a missing page</a>.</p>" as *u8)
131 let deadn: i64 = dd
132 v = pg_decide(prefix, dead, deadn, cs_ptr, cs_len, ncorpus)
133 rows = rows + 1; pass = pass + g_row(3, v, PG_REJECT_DEAD_LINK, "page links to a /wiki page absent from the corpus" as *u8)
134
135 // (v) PLACEHOLDER: fresh + an obvious placeholder marker -> REJECT PLACEHOLDER
136 let ph: *u8 = sys_mmap(2048)
137 var ph2: i64 = 0
138 ph2 = g_cat(ph, ph2, "<h1>Zero Trust</h1><p>epoch=1781730256</p><p>TODO: write this section</p>" as *u8)
139 let phn: i64 = ph2
140 v = pg_decide(prefix, ph, phn, cs_ptr, cs_len, ncorpus)
141 rows = rows + 1; pass = pass + g_row(4, v, PG_REJECT_PLACEHOLDER, "page with a TODO placeholder marker" as *u8)
142
143 // ---- verdict ----
144 g_w("NX-PUBGUARD-GATE rows=" as *u8); g_num(rows); g_w(" pass=" as *u8); g_num(pass); g_w("\n" as *u8)
145 if pass == rows {
146 let line: *u8 = sys_mmap(256)
147 var off: i64 = g_cat(line, 0, "PUBGUARD row=nx_wiki_publish_guard pdp rows=" as *u8)
148 off = g_catnum(line, off, rows); off = g_cat(line, off, " pass=" as *u8); off = g_catnum(line, off, pass)
149 off = g_cat(line, off, " verdict=PASS\n" as *u8)
150 let gf: i64 = sys_openat_append("knowledge/status/pubguard_gate.log" as *u8, 0x1a4)
151 if gf >= 0 { sys_write(gf, line, off); sys_close(gf) }
152 g_w("NX-PUBGUARD-GATE verdict=PASS -- fail-closed pre-publish guard recorded in pubguard_gate.log\n" as *u8)
153 sys_exit(0); return 0
154 }
155 g_w("NX-PUBGUARD-GATE verdict=FAIL -- NOT recorded (no fake-green)\n" as *u8)
156 sys_exit(1); return 1
157}