code wiki / (root) / nx_grab_ext_emit_gate.nx

nx_grab_ext_emit_gate.nx source

↩ module page · 266 lines · 13607 B

1// nx_grab_ext_emit_gate.nx -- REFEREE for nx_grab_ext_emit (/compare/mediaingest R10 ge_emit). 2// 3// IN-PROCESS AND NETWORK-FREE. It imports the emitter and calls its pure functions against a PLANTED 4// conf image held in memory, so nothing is written to disk, no browser is involved, and the production 5// knowledge/grab_ext.conf is never read or touched by this gate. 6// 7// THE LOAD-BEARING TOOTH IS THE MV2/MV3 STRUCTURAL SPLIT. The whole reason both twins are emitted from 8// one conf is that they must differ in STRUCTURE and never in POLICY: 9// MV2: background.scripts, browser_action, and <all_urls> INSIDE permissions 10// MV3: background.service_worker, action, and <all_urls> moved OUT to host_permissions 11// A wrong split is the defect that ships a Chrome extension the store rejects, or a Firefox one whose 12// host access silently does nothing. Testing that both manifests merely "contain the name" would pass 13// on a broken split, so the teeth below check the permissions array CONTENTS on each side, in both 14// directions -- present where it belongs and ABSENT where it does not. 15// license_tier: ORIGINAL 16import "nx_syscalls.nx" 17import "nx_grab_ext_emit.nx" 18import "nx_gate_verdict.nx" 19 20const T_CAP: i64 = 262144 21const T_SMALL: i64 = 4096 22 23// A planted conf: two comment lines (one of which contains a pipe, to prove comments are skipped and not 24// parsed as rows), one repeated key with three values, and every key the emitter needs. 25const T_CONF: *u8 = "# comment|not_a_row\nname|Test Grab\nversion|9.9\ndescription|planted\ngecko_id|t@nishi.local\nedge|https://edge.invalid\ncapture_path|/api/vault/capture\nmagnet_path|/t/m\nvideo_path|/t/v\nsession_header|X-Nishi-Session\nsession_key|nsess\nmedia_ext|m3u8\nmedia_ext|mp4\nmedia_ext|webm\nperm|webRequest\nperm|storage\nhost_perm|<all_urls>\n# trailing comment\n" 26 27// The same conf with the edge downgraded -- the neg-control for the https refusal. 28const T_CONF_HTTP: *u8 = "name|X\nversion|1\ndescription|d\ngecko_id|g\nedge|http://edge.invalid\ncapture_path|/c\nsession_header|H\nsession_key|k\nmedia_ext|mp4\nperm|storage\nhost_perm|<all_urls>\n" 29 30// A conf with a host_perm and ZERO perm rows. Two consecutive loops feed the ONE MV2 permissions array, 31// so an emitter that keys its separator off the loop index rather than a wrote-counter emits a LEADING 32// comma here -- invalid JSON that a browser rejects at load with no hint which row caused it. This 33// fixture exists to make that failure reachable; without it the bug is invisible on any normal conf. 34const T_CONF_NOPERM: *u8 = "name|Y\nversion|1\ndescription|d\ngecko_id|g\nedge|https://e.invalid\ncapture_path|/c\nsession_header|H\nsession_key|k\nmedia_ext|mp4\nhost_perm|<all_urls>\n" 35 36func t_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 37 38func t_find(buf: *u8, n: i64, lit: *u8, from: i64) -> i64 { 39 let ll: i64 = t_slen(lit) 40 if ll <= 0 { return 0 - 1 } 41 var i: i64 = from 42 while i + ll <= n { 43 var same: i64 = 1 44 var j: i64 = 0 45 while j < ll { if buf[i + j] != lit[j] { same = 0 } j = j + 1 } 46 if same == 1 { return i } 47 i = i + 1 48 } 49 return 0 - 1 50} 51 52func t_has(buf: *u8, n: i64, lit: *u8) -> i64 { if t_find(buf, n, lit, 0) >= 0 { return 1 } return 0 } 53 54// Extent of the JSON array that follows `key` -- from the '[' after the key to its matching ']'. 55// Returns the length and sets off_out[0]; -1 when the key or a closing bracket is absent. 56func t_array_of(buf: *u8, n: i64, key: *u8, off_out: *i64) -> i64 { 57 off_out[0] = 0 - 1 58 let k: i64 = t_find(buf, n, key, 0) 59 if k < 0 { return 0 - 1 } 60 // Separate cursor and exit FLAG: writing a sentinel into the cursor to break the loop destroys the 61 // very position the caller needs, and the estate measured that defect four times in one day. 62 var i: i64 = k 63 var open: i64 = 0 - 1 64 var scanning: i64 = 1 65 while scanning == 1 { 66 if i >= n { scanning = 0 } 67 else { 68 if buf[i] == (91 as u8) { open = i; scanning = 0 } else { i = i + 1 } 69 } 70 } 71 if open < 0 { return 0 - 1 } 72 var e: i64 = open 73 var close: i64 = 0 - 1 74 scanning = 1 75 while scanning == 1 { 76 if e >= n { scanning = 0 } 77 else { 78 if buf[e] == (93 as u8) { close = e; scanning = 0 } else { e = e + 1 } 79 } 80 } 81 if close < 0 { return 0 - 1 } 82 off_out[0] = open 83 return close - open + 1 84} 85 86func main() -> i64 { 87 gv_head("=== nx_grab_ext_emit_gate -- the extension is EMITTED FROM DATA, both twins (mediaingest R10) ===" as *u8) 88 let c: *i64 = gv_ctr() 89 let cn: i64 = t_slen(T_CONF) 90 let off: *i64 = sys_mmap(16) as *i64 91 92 // ---- ANTI-VACUITY FIRST: the planted conf must actually carry what every tooth below inspects, 93 // so a fixture that lost its rows cannot make this gate pass by examining nothing. 94 var fx: i64 = 0 95 if gx_count(T_CONF, cn, "media_ext" as *u8) == 3 { 96 if gx_count(T_CONF, cn, "perm" as *u8) == 2 { 97 if gx_count(T_CONF, cn, "host_perm" as *u8) == 1 { fx = 1 } 98 } 99 } 100 gv_check("fixture-reached-the-condition-conf-carries-3-media-2-perm-1-hostperm" as *u8, fx, c) 101 102 // ---- conf reader ---- 103 let vl: i64 = gx_nth(T_CONF, cn, "version" as *u8, 0, off) 104 var t: i64 = 0 105 if vl == 3 { if T_CONF[off[0]] == (57 as u8) { t = 1 } } 106 gv_check("conf-reads-a-single-value" as *u8, t, c) 107 108 // A comment line containing a pipe must NOT be parsed as a row. If it were, this key would resolve. 109 t = 0 110 if gx_nth(T_CONF, cn, "# comment" as *u8, 0, off) < 0 { t = 1 } 111 gv_check("neg-control-a-commented-line-with-a-pipe-is-not-a-row" as *u8, t, c) 112 113 t = 0 114 if gx_nth(T_CONF, cn, "no_such_key" as *u8, 0, off) < 0 { t = 1 } 115 gv_check("neg-control-absent-key-returns-minus-one" as *u8, t, c) 116 117 // repeated key, read by index 118 let m0: i64 = gx_nth(T_CONF, cn, "media_ext" as *u8, 0, off) 119 var o0: i64 = off[0] 120 let m2: i64 = gx_nth(T_CONF, cn, "media_ext" as *u8, 2, off) 121 var o2: i64 = off[0] 122 t = 0 123 if m0 == 4 { if m2 == 4 { if T_CONF[o0] == (109 as u8) { if T_CONF[o2] == (119 as u8) { t = 1 } } } } 124 gv_check("repeated-key-is-read-by-index-first-and-third-differ" as *u8, t, c) 125 126 // ---- the media alternation: ONE list, and it is what the emitted regex is built from ---- 127 let alt: *u8 = sys_mmap(T_SMALL) 128 let al: i64 = gx_media_alt(T_CONF, cn, alt, T_SMALL) 129 t = 0 130 if al > 0 { if t_has(alt, al, "m3u8|mp4|webm" as *u8) == 1 { t = 1 } } 131 gv_check("media-alternation-joins-every-conf-row-in-order" as *u8, t, c) 132 133 // ---- MV2 ---- 134 let mv2: *u8 = sys_mmap(T_CAP) 135 let n2: i64 = gx_emit_mv2(T_CONF, cn, mv2, T_CAP) 136 t = 0 137 if n2 > 0 { t = 1 } 138 gv_check("mv2-manifest-emits" as *u8, t, c) 139 140 t = 0 141 if t_has(mv2, n2, "\"manifest_version\": 2" as *u8) == 1 { t = 1 } 142 gv_check("mv2-declares-manifest-version-2" as *u8, t, c) 143 t = 0 144 if t_has(mv2, n2, "\"background\": { \"scripts\"" as *u8) == 1 { t = 1 } 145 gv_check("mv2-uses-background-scripts" as *u8, t, c) 146 t = 0 147 if t_has(mv2, n2, "\"browser_action\"" as *u8) == 1 { t = 1 } 148 gv_check("mv2-uses-browser-action" as *u8, t, c) 149 t = 0 150 if t_has(mv2, n2, "\"service_worker\"" as *u8) == 0 { t = 1 } 151 gv_check("neg-control-mv2-does-NOT-use-a-service-worker" as *u8, t, c) 152 t = 0 153 if t_has(mv2, n2, "\"host_permissions\"" as *u8) == 0 { t = 1 } 154 gv_check("neg-control-mv2-has-NO-host-permissions-key" as *u8, t, c) 155 156 // THE SPLIT, MV2 SIDE: <all_urls> must be INSIDE the permissions array. 157 let pl2: i64 = t_array_of(mv2, n2, "\"permissions\"" as *u8, off) 158 t = 0 159 if pl2 > 0 { if t_has(((mv2 as i64) + off[0]) as *u8, pl2, "<all_urls>" as *u8) == 1 { t = 1 } } 160 gv_check("mv2-permissions-array-CARRIES-all-urls" as *u8, t, c) 161 162 // ---- MV3 ---- 163 let mv3: *u8 = sys_mmap(T_CAP) 164 let n3: i64 = gx_emit_mv3(T_CONF, cn, mv3, T_CAP) 165 t = 0 166 if n3 > 0 { t = 1 } 167 gv_check("mv3-manifest-emits" as *u8, t, c) 168 t = 0 169 if t_has(mv3, n3, "\"manifest_version\": 3" as *u8) == 1 { t = 1 } 170 gv_check("mv3-declares-manifest-version-3" as *u8, t, c) 171 t = 0 172 if t_has(mv3, n3, "\"service_worker\": \"background.js\"" as *u8) == 1 { t = 1 } 173 gv_check("mv3-uses-a-background-service-worker" as *u8, t, c) 174 t = 0 175 if t_has(mv3, n3, "\"host_permissions\"" as *u8) == 1 { t = 1 } 176 gv_check("mv3-declares-host-permissions" as *u8, t, c) 177 t = 0 178 if t_has(mv3, n3, "\"browser_action\"" as *u8) == 0 { t = 1 } 179 gv_check("neg-control-mv3-does-NOT-use-browser-action" as *u8, t, c) 180 181 // THE SPLIT, MV3 SIDE -- the tooth that a broken emitter fails. <all_urls> must have MOVED OUT of 182 // permissions and into host_permissions. Checking only that host_permissions exists would pass on an 183 // emitter that wrote <all_urls> into BOTH, which is exactly the MV3 packaging error. 184 let pl3: i64 = t_array_of(mv3, n3, "\"permissions\"" as *u8, off) 185 t = 0 186 if pl3 > 0 { if t_has(((mv3 as i64) + off[0]) as *u8, pl3, "<all_urls>" as *u8) == 0 { t = 1 } } 187 gv_check("mv3-permissions-array-does-NOT-carry-all-urls-it-moved-to-host-permissions" as *u8, t, c) 188 189 let hl3: i64 = t_array_of(mv3, n3, "\"host_permissions\"" as *u8, off) 190 t = 0 191 if hl3 > 0 { if t_has(((mv3 as i64) + off[0]) as *u8, hl3, "<all_urls>" as *u8) == 1 { t = 1 } } 192 gv_check("mv3-host-permissions-array-CARRIES-all-urls" as *u8, t, c) 193 194 // ---- the empty-perm array: no leading comma on either twin ---- 195 let en0: i64 = t_slen(T_CONF_NOPERM) 196 let mv2b: *u8 = sys_mmap(T_CAP) 197 let n2b: i64 = gx_emit_mv2(T_CONF_NOPERM, en0, mv2b, T_CAP) 198 t = 0 199 if n2b > 0 { 200 if t_has(mv2b, n2b, "[, " as *u8) == 0 { if t_has(mv2b, n2b, "<all_urls>" as *u8) == 1 { t = 1 } } 201 } 202 gv_check("neg-control-mv2-with-zero-perm-rows-emits-no-leading-comma-and-still-carries-the-host-perm" as *u8, t, c) 203 let mv3b: *u8 = sys_mmap(T_CAP) 204 let n3b: i64 = gx_emit_mv3(T_CONF_NOPERM, en0, mv3b, T_CAP) 205 t = 0 206 if n3b > 0 { if t_has(mv3b, n3b, "[, " as *u8) == 0 { t = 1 } } 207 gv_check("neg-control-mv3-with-zero-perm-rows-emits-no-leading-comma" as *u8, t, c) 208 209 // ---- POLICY IS IDENTICAL ACROSS TWINS even though STRUCTURE differs ---- 210 t = 0 211 if t_has(mv2, n2, "\"name\": \"Test Grab\"" as *u8) == 1 { 212 if t_has(mv3, n3, "\"name\": \"Test Grab\"" as *u8) == 1 { t = 1 } 213 } 214 gv_check("both-twins-carry-the-same-name-from-the-one-conf" as *u8, t, c) 215 t = 0 216 if t_has(mv2, n2, "\"version\": \"9.9\"" as *u8) == 1 { 217 if t_has(mv3, n3, "\"version\": \"9.9\"" as *u8) == 1 { t = 1 } 218 } 219 gv_check("both-twins-carry-the-same-version-from-the-one-conf" as *u8, t, c) 220 221 // ---- the emitted scripts ---- 222 let bg: *u8 = sys_mmap(T_CAP) 223 let nb: i64 = gx_emit_bg(T_CONF, cn, bg, T_CAP) 224 t = 0 225 if nb > 0 { if t_has(bg, nb, "m3u8|mp4|webm" as *u8) == 1 { t = 1 } } 226 gv_check("background-regex-is-built-from-the-conf-media-rows" as *u8, t, c) 227 t = 0 228 if t_has(bg, nb, "https://edge.invalid" as *u8) == 1 { t = 1 } 229 gv_check("background-carries-the-conf-edge-host" as *u8, t, c) 230 t = 0 231 if t_has(bg, nb, "/api/vault/capture" as *u8) == 1 { t = 1 } 232 gv_check("background-posts-to-the-capture-chokepoint-from-conf" as *u8, t, c) 233 // R11: the whole point is that no native companion exists. If a future edit reaches for native 234 // messaging, this tooth fails and the reviewer is told which promise was broken. 235 t = 0 236 if t_has(bg, nb, "connectNative" as *u8) == 0 { 237 if t_has(bg, nb, "nativeMessaging" as *u8) == 0 { t = 1 } 238 } 239 gv_check("R11-neg-control-emitted-background-uses-NO-native-messaging-host" as *u8, t, c) 240 // nx_cc forbids '!' inside a string literal, so the emitted JS must never contain one. A future edit 241 // that reaches for it would fail to COMPILE, but this tooth says so in words rather than as a lexer error. 242 t = 0 243 if t_has(bg, nb, "===" as *u8) == 1 { t = 1 } 244 gv_check("emitted-js-uses-explicit-equality-the-lexer-forbids-bang-in-a-literal" as *u8, t, c) 245 246 let ct: *u8 = sys_mmap(T_CAP) 247 let nc: i64 = gx_emit_content(T_CONF, cn, ct, T_CAP) 248 t = 0 249 if nc > 0 { if t_has(ct, nc, "location.origin === EDGE" as *u8) == 1 { t = 1 } } 250 gv_check("content-script-harvests-the-session-ONLY-on-the-estate-origin" as *u8, t, c) 251 252 // ---- the https refusal, tested as a PREDICATE (the emitter's own guard calls sys_exit, which a 253 // gate cannot survive in-process; gx_starts is the decision that guard branches on) ---- 254 let en: i64 = t_slen(T_CONF_HTTP) 255 let el: i64 = gx_nth(T_CONF_HTTP, en, "edge" as *u8, 0, off) 256 t = 0 257 if el > 0 { if gx_starts(T_CONF_HTTP, off[0], el, "https://" as *u8) == 0 { t = 1 } } 258 gv_check("neg-control-an-http-edge-fails-the-https-predicate-the-emitter-refuses-on" as *u8, t, c) 259 let el2: i64 = gx_nth(T_CONF, cn, "edge" as *u8, 0, off) 260 t = 0 261 if el2 > 0 { if gx_starts(T_CONF, off[0], el2, "https://" as *u8) == 1 { t = 1 } } 262 gv_check("an-https-edge-passes-the-same-predicate" as *u8, t, c) 263 264 return gv_verdict("nx_grab_ext_emit_gate" as *u8, c, 265 "pure emitters against a planted in-memory conf -- nothing is written to disk, the production knowledge/grab_ext.conf is never read, and no browser is involved; a green here says the two manifests are structurally correct for their engines and that both twins carry one policy, and says NOTHING about whether either extension loads in a real browser, which is a separate declared step" as *u8) 266}