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}