code wiki / _hdl_build / nx_trustfence_lib.nx
nx_trustfence_lib.nx source
↩ module page · 140 lines · 6682 B
1// nx_trustfence_lib.nx -- LangIntel LI9 SHARED trust-tier classifier (pure, NO I/O, NO main).
2// SEALED verdict codes so BOTH the CLI (nx_langintel_trustfence) and the CI fixture gate
3// (nx_langintel_trustfence_gate) reuse ONE ltg_classify_code = single source of truth (Rule 15 DRY,
4// the atlas OO-consolidation directive). Provenance-only trust: tier-1 IFF merged + real merge_commit_sha +
5// base.repo.full_name == the canonical owner/repo (an attacker cannot merge into it). Branch identity is
6// evidence, NOT gated (default_branch is CURRENT, base.ref is HISTORICAL -- master->main rename would
7// false-reject a genuine gold patch). Consolidates onto nx_ingest_base (ib_find/ib_jstr/ib_slen).
8// Read-only external, NO exec (Rule 26). license_tier: ORIGINAL
9import "nx_ingest_base.nx"
10import "nx_syscalls.nx"
11
12const LTG_VCAP: i64 = 1024
13
14// sealed verdicts (Rule 6 structured):
15const LTG_ACCEPT: i64 = 1
16const LTG_REJ_NOT_MERGED: i64 = 2
17const LTG_REJ_NO_MERGE_SHA: i64 = 3
18const LTG_REJ_NO_BASE: i64 = 4
19const LTG_REJ_BASE_SPAN: i64 = 5
20const LTG_REJ_NO_BASE_REF: i64 = 6
21const LTG_REJ_NO_BASE_REPO: i64 = 7
22const LTG_REJ_BASE_REPO_SPAN: i64 = 8
23const LTG_REJ_NO_FULL_NAME: i64 = 9
24const LTG_REJ_NOT_CANONICAL: i64 = 10
25
26func ltg_qkey(word: *u8, out: *u8) -> i64 {
27 out[0] = 34 as u8
28 var i: i64 = 0
29 while word[i] != (0 as u8) { out[i+1] = word[i]; i = i + 1 }
30 out[i+1] = 34 as u8
31 out[i+2] = 0 as u8
32 return 0
33}
34func ltg_streq(a: *u8, b: *u8) -> i64 {
35 var i: i64 = 0
36 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
37 if b[i] != (0 as u8) { return 0 }
38 return 1
39}
40// balanced {..} object at/after `from`, string-aware (ignores braces in quoted strings, honors backslash).
41// se[0]='{' index, se[1]=index AFTER matching '}'. 1 ok / 0 unbalanced.
42func ltg_obj_span(buf: *u8, n: i64, from: i64, se: *i64) -> i64 {
43 var i: i64 = from
44 var start: i64 = 0 - 1
45 var g: i64 = 1
46 while g == 1 {
47 if i >= n { g = 0 } else { if buf[i] == (123 as u8) { start = i; g = 0 } else { i = i + 1 } }
48 }
49 if start < 0 { return 0 }
50 var depth: i64 = 0
51 var instr: i64 = 0
52 var j: i64 = start
53 var go: i64 = 1
54 while go == 1 {
55 if j >= n { go = 0 }
56 else {
57 let c: i64 = buf[j] as i64
58 if instr == 1 {
59 if c == 92 { j = j + 1 } else { if c == 34 { instr = 0 } }
60 } else {
61 if c == 34 { instr = 1 } else { if c == 123 { depth = depth + 1 } else { if c == 125 { depth = depth - 1; if depth == 0 { se[0] = start; se[1] = j + 1; return 1 } } } }
62 }
63 j = j + 1
64 }
65 }
66 return 0
67}
68// 1 if key's bool value is true, 0 if false/other, -1 if key absent. scans [from,n).
69func ltg_bool(buf: *u8, n: i64, key: *u8, from: i64) -> i64 {
70 let p: i64 = ib_find(buf, n, key, from)
71 if p < 0 { return 0 - 1 }
72 var i: i64 = p + ib_slen(key)
73 var g: i64 = 1
74 while g == 1 {
75 if i >= n { return 0 - 1 }
76 let c: i64 = buf[i] as i64
77 if c == 58 { i = i + 1 } else { if c == 32 { i = i + 1 } else { if c == 9 { i = i + 1 } else { if c == 10 { i = i + 1 } else { if c == 13 { i = i + 1 } else { g = 0 } } } } }
78 }
79 if buf[i] == (116 as u8) { return 1 }
80 return 0
81}
82// PURE classifier: fills msha/bfull/bref/bdef (caller buffers, LTG_VCAP; empty if not reached) with the
83// extracted evidence, returns a sealed LTG_* code. NO I/O -- the CLI and the CI gate both call this.
84func ltg_classify_code(buf: *u8, n: i64, expect_full: *u8, msha: *u8, bfull: *u8, bref: *u8, bdef: *u8) -> i64 {
85 msha[0] = 0 as u8; bfull[0] = 0 as u8; bref[0] = 0 as u8; bdef[0] = 0 as u8
86 let bs0: i64 = ib_find(buf, n, "{" as *u8, 0)
87 var bs: i64 = 0
88 if bs0 >= 0 { bs = bs0 }
89 let kb: *u8 = sys_mmap(128)
90 ltg_qkey("merged" as *u8, kb)
91 let merged: i64 = ltg_bool(buf, n, kb, bs)
92 if merged != 1 { return LTG_REJ_NOT_MERGED }
93 ltg_qkey("merge_commit_sha" as *u8, kb)
94 let mr: i64 = ib_jstr(buf, n, kb, bs, msha, LTG_VCAP)
95 if mr < 0 { return LTG_REJ_NO_MERGE_SHA }
96 let bse: *i64 = sys_mmap(16) as *i64
97 ltg_qkey("base" as *u8, kb)
98 let bp: i64 = ib_find(buf, n, kb, bs)
99 if bp < 0 { return LTG_REJ_NO_BASE }
100 if ltg_obj_span(buf, n, bp, bse) == 0 { return LTG_REJ_BASE_SPAN }
101 let bstart: i64 = bse[0]
102 let bend: i64 = bse[1]
103 ltg_qkey("ref" as *u8, kb)
104 let rr: i64 = ib_jstr(buf, bend, kb, bstart, bref, LTG_VCAP)
105 if rr < 0 { return LTG_REJ_NO_BASE_REF }
106 let rse: *i64 = sys_mmap(16) as *i64
107 ltg_qkey("repo" as *u8, kb)
108 let rp: i64 = ib_find(buf, bend, kb, bstart)
109 if rp < 0 { return LTG_REJ_NO_BASE_REPO }
110 if ltg_obj_span(buf, bend, rp, rse) == 0 { return LTG_REJ_BASE_REPO_SPAN }
111 let rstart: i64 = rse[0]
112 let rend: i64 = rse[1]
113 ltg_qkey("full_name" as *u8, kb)
114 let fr: i64 = ib_jstr(buf, rend, kb, rstart, bfull, LTG_VCAP)
115 if fr < 0 { return LTG_REJ_NO_FULL_NAME }
116 ltg_qkey("default_branch" as *u8, kb)
117 let dr: i64 = ib_jstr(buf, rend, kb, rstart, bdef, LTG_VCAP)
118 if dr < 0 { bdef[0] = 63 as u8; bdef[1] = 0 as u8 }
119 if ltg_streq(bfull, expect_full) == 0 { return LTG_REJ_NOT_CANONICAL }
120 return LTG_ACCEPT
121}
122func ltg_is_accept(code: i64) -> i64 { if code == LTG_ACCEPT { return 1 } return 0 }
123func ltg_reason(code: i64) -> *u8 {
124 if code == LTG_REJ_NOT_MERGED { return "pr-not-merged" as *u8 }
125 if code == LTG_REJ_NO_MERGE_SHA { return "no-merge-commit-sha" as *u8 }
126 if code == LTG_REJ_NO_BASE { return "no-base-object" as *u8 }
127 if code == LTG_REJ_BASE_SPAN { return "base-span-unbalanced" as *u8 }
128 if code == LTG_REJ_NO_BASE_REF { return "no-base-ref" as *u8 }
129 if code == LTG_REJ_NO_BASE_REPO { return "no-base-repo" as *u8 }
130 if code == LTG_REJ_BASE_REPO_SPAN { return "base-repo-span-unbalanced" as *u8 }
131 if code == LTG_REJ_NO_FULL_NAME { return "no-base-repo-full_name" as *u8 }
132 if code == LTG_REJ_NOT_CANONICAL { return "base-repo-not-canonical" as *u8 }
133 return "unknown" as *u8
134}
135func ltg_fix(code: i64) -> *u8 {
136 if code == LTG_REJ_NOT_MERGED { return "ingest ONLY merged PRs -- an unmerged/closed PR is not a canonical fix; skip it" as *u8 }
137 if code == LTG_REJ_NO_MERGE_SHA { return "require a real merge_commit_sha -- null means not actually merged into a branch" as *u8 }
138 if code == LTG_REJ_NOT_CANONICAL { return "base.repo.full_name != expected canonical owner/repo -- likely a FORK or wrong project; ingest ONLY from the canonical repo (an attacker cannot merge into it)" as *u8 }
139 return "malformed PR json -- refetch via nx_ghfetch <pr-api-url> <file>" as *u8
140}